home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / migd / global.c < prev    next >
C/C++ Source or Header  |  1992-06-16  |  108KB  |  3,804 lines

  1. /* 
  2.  * global.c --
  3.  *
  4.  *    Routines to manage the global loadavg data base.  Only one
  5.  *    process is permitted to open the global pdev in master
  6.  *    mode and service requests on it.  All hosts run a daemon that
  7.  *    communicates periodically with the global server.  Clients
  8.  *    communicate with the global server to obtain load info and request
  9.  *    idle hosts.  Idle hosts may be released explicitly by ioctls with
  10.  *    the server, or implicitly upon closing the pdev connection.
  11.  *
  12.  *     The global server maintains an array of structures, one per host,
  13.  *    with the load information for each host.  The hosts are linked into
  14.  *    idle lists, which are distinguished by architecture type and
  15.  *    the type of processes running on the hosts. If a host is completely
  16.  *    idle, then it is available for any type of process.  On the other
  17.  *    hand, it might be used by a low priority process, and it could still
  18.  *    be used by a higher-priority process but not by another low priority
  19.  *    process.  In each case, the availability is determined by the
  20.  *    number of processors on the host, so a host with 4 processors and
  21.  *    three background jobs is presumed to be capable of a fourth background
  22.  *    job or up to 4 higher-priority jobs.  The queue for completely
  23.  *    idle hosts is sorted in order of idle time, but the other queues
  24.  *    are just FIFO since if a host already has stuff on it then it
  25.  *     is less likely to matter how long it's already been idle. (Maybe
  26.  *    this isn't true; in that case, sorting the other queues is
  27.  *    always possible.)
  28.  *
  29.  *    In addition, the server maintains information about each
  30.  *    process that is using idle hosts, and each user.  The per-user
  31.  *    information is not yet used but may be used to implement a fairness
  32.  *    policy at some future date.  The per-process information is associated
  33.  *    with the pdev handle for the client.  If the pdev is closed,
  34.  *    all hosts used by that process are marked available.
  35.  *
  36.  * Copyright 1989, 1990 Regents of the University of California
  37.  * Permission to use, copy, modify, and distribute this
  38.  * software and its documentation for any purpose and without
  39.  * fee is hereby granted, provided that the above copyright
  40.  * notice appear in all copies.  The University of California
  41.  * makes no representations about the suitability of this
  42.  * software for any purpose.  It is provided "as is" without
  43.  * express or implied warranty.
  44.  */
  45.  
  46. #ifndef lint
  47. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 2.5 92/06/16 20:51:54 jhh Exp $ SPRITE (Berkeley)";
  48. #endif /* not lint */
  49.  
  50.  
  51. #include <sprite.h>
  52. #include <string.h>
  53. #include <list.h>
  54. #include <errno.h>
  55. #include <status.h>
  56. #include "syslog.h"
  57. #include <bstring.h>
  58. #include <fs.h>
  59. #include <kernel/fs.h>
  60. #include <sys/types.h>
  61. #include <sys/time.h>
  62. #include <unistd.h>
  63. #include <stdlib.h>
  64. #include <stdio.h>
  65. #include <sys/dir.h>
  66. #include <sys/file.h>
  67. #include <sys/stat.h>
  68. #include <host.h>
  69. #include <signal.h>
  70. #include <pdev.h>
  71. #include <kernel/net.h>
  72. #include "mig.h"
  73. #include "migd.h"
  74. #include "migPdev.h"
  75.  
  76. /* 
  77.  * Define a structure for keeping track of info we need to send to
  78.  * clients.  Each message is a single int.
  79.  */
  80. typedef struct {
  81.     List_Links links;        /* Link to next message. */
  82.     int msg;            /* Integer-valued message to tell client. */
  83. } MessageBlock;
  84.  
  85. /* 
  86.  * A structure is used to keep track of outstanding requests,
  87.  * i.e., idle hosts that have been assigned to a process and not yet
  88.  * returned.   It points back to the open stream info and to two linked
  89.  * lists, one that's per stream and one that's per host.
  90.  */
  91. typedef struct RequestInfo {
  92.     List_Links  nextClientRequest;    /* Link to next request by same
  93.                        client. */
  94.     List_Links  nextHostRequest;    /* Link to next request for this
  95.                        host. */
  96.     List_Links  nextInUse;        /* Link to next request for this
  97.                        machine type and priority. */
  98.     int timestamp;            /* Time of request. */
  99.     int priority;            /* Priority of processes. */
  100.     int numProcessors;            /* Number of processors assigned. */
  101.     int idleTime;            /* Idle time of host at time of
  102.                        request (in case of eviction,
  103.                        for statistics). */
  104.     int flags;                /* Flags applied to request. */
  105.     union {
  106.     Migd_OpenStreamInfo *cltPtr;     /* Pointer back to open stream info
  107.                        for client. */
  108.     int processID;            /* ID of process, if agent. */
  109.     } client;
  110.     struct Migd_Info *migdPtr;        /* Pointer back to host assigned. */
  111. } RequestInfo;
  112.  
  113. #define NEXT_HOST_REQUEST_TO_INFO(listPtr) \
  114.     ( (RequestInfo *)((int)(listPtr) - sizeof(List_Links)) )
  115.  
  116. #define NEXT_HOST_IN_USE_TO_INFO(listPtr) \
  117.     ( (RequestInfo *)((int)(listPtr) - 2 * sizeof(List_Links)) )
  118.  
  119. /*
  120.  * Arguments to RevokePermission().  Indicates what to do with client and
  121.  * what to do with statistics gathering. 
  122.  */
  123. typedef enum {
  124.     REVOKE_EVICT,        /* Evicting processes. */
  125.     REVOKE_STOLEN,        /* Claiming for fairness purposes. */
  126.     REVOKE_IDLE,        /* Thought host was unused for a long time. */
  127. } RevokeAction;
  128.  
  129. /*
  130.  * Define the number of seconds we'll wait before notifying a process
  131.  * about new hosts being available if we just stole hosts from it.
  132.  */
  133. #define MIGD_STOLE_WINDOW 30
  134.  
  135.  
  136. static int maxArchTypes = MIG_MAX_ARCH_TYPES;      /* number of elements
  137.                            in arrays per-type */
  138. static char **archTypesArray;   /* array of strings mapping types to indexes
  139.                    in these arrays */
  140.  
  141. static int maxHosts = NET_NUM_SPRITE_HOSTS; /* number of hosts in arrays
  142.                            per-host */
  143. static int maxKnownHost = 0;    /* Highest known host ID. */
  144.  
  145. static Migd_Info **migInfoArray;    /* array of host info pointers */
  146. static List_Links *idleHostsArray[MIG_NUM_PRIORITIES];
  147.                     /* array of lists of idle hosts,
  148.                        indexed by type and priority. */
  149. static List_Links *inUseArray[MIG_NUM_PRIORITIES];
  150.                     /* array of lists of host requests,
  151.                        indexed by type and priority. */
  152. static List_Links *waitingLists[MIG_NUM_PRIORITIES];
  153.                     /* array of lists of waiting clients,
  154.                        indexed by type. */
  155.  
  156. static int hostsUp = 0;        /* Total number of hosts up, used for
  157.                    determining when it's safe to exit after
  158.                    termination. */
  159. static int hostCounts[MIG_MAX_ARCH_TYPES][MIG_NUM_STATES];
  160.                 /* Counts per-architecture, per-state. */
  161.  
  162. static int lastRequestHost = -1; /* ID of last host making a request. */
  163.  
  164. /*
  165.  * Global variables.
  166.  */
  167. int global_Debug = 0;        /* enable debugging info? */
  168.  
  169. int global_CheckpointInterval = MIG_TIMEOUT;    /* Interval for saving
  170.                            checkpoints. */
  171.  
  172. Mig_Stats global_Stats;        /* Statistics, maintained mostly by this
  173.                    file. */
  174.  
  175. #ifndef MIGD_CHECKPOINT_FILE
  176. #define MIGD_CHECKPOINT_FILE "/sprite/admin/migd/check"
  177. #endif /* MIGD_CHECKPOINT_FILE */
  178.  
  179. #ifndef MIGD_LOCK_FILE
  180. #define MIGD_LOCK_FILE "/sprite/admin/migd/lock"
  181. #endif /* MIGD_LOCK_FILE */
  182.  
  183. #ifndef MIGD_LOG_FILE
  184. #define MIGD_LOG_FILE "/sprite/admin/migd/log"
  185. #endif /* MIGD_LOG_FILE */
  186.  
  187. /* 
  188.  * Things to keep track of the files used (errors, and lock file).
  189.  */
  190. char *global_ErrorFile = NULL;    /* Place to write host-daemon errors,
  191.                    initialized in main. */
  192. static int  lockDesc;        /* Descriptor for lock file. */
  193. static struct stat descAtts;    /* Attributes of lock file. */
  194.  
  195. static void CreateMigdRecord();  /* Allocate a Migd_Info record. */
  196. static void RestoreCheckPoint(); /* Restore checkpoint from file. */
  197. static void SaveCheckPoint();      /* Save checkpoint to file. */
  198. static void CheckHostStatus();      /* Check the status of a host after an
  199.                     update. */
  200. static int  RemoveHost();      /* Remove host from list of hosts. */
  201. static int  HostIsIdle();      /* Check for host being idle. */
  202. static void InsertIdle();      /* Add host to list of idle hosts. */
  203. static void WakeupWaiters();      /* Wake up processes that want more hosts. */
  204. static void RecordEvictions();      /* Remove host from idle list and notify
  205.                     clients of evictions. */
  206. static void ForceHostIdle();      /* Make a host seem idle. */
  207. static void TellClient();      /* Notify a client about a change in
  208.                     status. */
  209. static int CheckFairness();      /* Check on host allocation fairness. */
  210. static void RevokePermission();     /* Notify a client that its permission to
  211.                     use a host has been revoked. */
  212. static Migd_Info *CltToMigd();     /* Map from client info to migd record. */
  213.  
  214. static void InitStats();    /* Initialize statistics. */
  215. static void DumpStats();    /* Dump statistics to file. */
  216. static int  ReadStats();    /* Read statistics from file. */
  217.  
  218.  
  219. /*
  220.  *----------------------------------------------------------------------
  221.  *
  222.  * Global_Init --
  223.  *
  224.  *    Initialize state of the global server.   Called when a process
  225.  *    forks and the child tries to become the master for the global
  226.  *    pdev.
  227.  *
  228.  * Results:
  229.  *    0 for successful completion, -1 for error, with errno indicating
  230.  *    the nature of the error.
  231.  *
  232.  * Side effects:
  233.  *    Opens pseudo-device, allocates arrays and assigns architecture strings
  234.  *    to indexes.
  235.  *
  236.  *----------------------------------------------------------------------
  237.  */
  238.  
  239. int
  240. Global_Init()
  241. {
  242.     Host_Entry *hostPtr;
  243.     int i, j;
  244.     Time    period;
  245.     char pidString[10];
  246.     FILE *logFile;
  247.  
  248.     migd_Pid = getpid();
  249.     
  250.     if (migd_LogToFiles) {
  251.     freopen(migd_GlobalErrorName, "a", stderr);
  252. #ifdef SEEK_REOPEN    
  253.     fseek(stderr, 0L, L_XTND);
  254. #endif /* SEEK_REOPEN */
  255.     if (fcntl(fileno(stderr), F_SETFL, FAPPEND) < 0) {
  256.         perror("fcntl");
  257.     }
  258.     }
  259.     
  260.     if (global_Debug > 0) {
  261.     int t = time(0);
  262.     fprintf(stderr, "Global_Init - process %x version %u on host %s:\n",
  263.         migd_Pid, migd_Version, migd_HostName);
  264.     fprintf(stderr, "\trun at %s", ctime(&t));
  265.     }
  266.  
  267.     /*
  268.      * We're trying to become the master for the global pdev.
  269.      */
  270.     migd_GlobalMaster = 1;
  271.  
  272.     /*
  273.      * Open pdev.  If someone else beats us to it, that's fine, let
  274.      * him handle it.
  275.      */
  276.     if (MigPdev_OpenMaster() < 0){
  277.     return(-1);
  278.     }
  279.  
  280.     /*
  281.      * Create a regular file that we use for detecting changes in master,
  282.      * since unlinking a pdev may cause the file descriptor to be reused
  283.      * prematurely.  If we can't create it, there's an error.  It may
  284.      * be that right after we unlink it, someone else creates it, in
  285.      * which case that process will become the global master.  The pdev
  286.      * is always opened successfully before the lock file is removed
  287.      * and rewritten.
  288.      */
  289.     (void) unlink(MIGD_LOCK_FILE);
  290.     lockDesc = open(MIGD_LOCK_FILE, O_WRONLY|O_CREAT|O_EXCL, 0644);
  291.     if (lockDesc < 0) {
  292.     perror("open (lock file)");
  293.     return(-1);
  294.     }
  295.     sprintf(pidString, "%x\n", migd_Pid);
  296.     if (write(lockDesc, pidString, strlen(pidString) + 1) !=
  297.     strlen(pidString) + 1) {
  298.     perror("write");
  299.     return(-1);
  300.     }
  301.     
  302.     if (fstat(lockDesc, &descAtts) < 0) {
  303.     SYSLOG1(LOG_ERR, "Exiting: unable to stat lock descriptor: %s.\n",
  304.            strerror(errno));
  305.     exit(1);
  306.     }
  307.  
  308.     /*
  309.      * Log a record saying we've started.  This is to a separate file from
  310.      * the usual error/debug log.
  311.      */
  312.     logFile = fopen(MIGD_LOG_FILE, "a");
  313.     if (logFile == (FILE *) NULL) {
  314.     fprintf(stderr, "Error opening %s: %s\n", MIGD_LOG_FILE, 
  315.         strerror(errno));
  316.     } else {
  317.     int t = time(0);
  318.     fprintf(logFile, "process %x version %u on host %s:\n",
  319.         migd_Pid, migd_Version, migd_HostName);
  320.     fprintf(logFile, "\trun at %s", ctime(&t));
  321.     fclose(logFile);
  322.     }
  323.     
  324.     /*
  325.      * We are the master.  Initialize the arrays of hosts and
  326.      * architecture types.
  327.      */
  328.     archTypesArray = (char **) Malloc(sizeof(char *) * maxArchTypes);
  329.     bzero((char *) archTypesArray, sizeof(char *) * maxArchTypes);
  330.  
  331.     migInfoArray = (Migd_Info **) Malloc(sizeof(Migd_Info *) *
  332.                     (maxHosts + 1));
  333.     bzero((char *) migInfoArray, sizeof(Migd_Info *) *
  334.       (maxHosts + 1));
  335.  
  336.     /*
  337.      * Go through the host database and set up an empty entry for
  338.      * each host.  Also, find all the architecture types to establish
  339.      * a mapping from host to type.
  340.      */
  341.     Host_Start();
  342.     while (1) {
  343.     hostPtr = Host_Next();
  344.     if (hostPtr == (Host_Entry *) NULL) {
  345.         break;
  346.     }
  347.     CreateMigdRecord(hostPtr);
  348.     }
  349.     Host_End();
  350.  
  351.     for (i = 0; i < MIG_NUM_PRIORITIES; i++) {
  352.     idleHostsArray[i] = (List_Links *) Malloc(maxArchTypes *
  353.                           sizeof(List_Links));
  354.     inUseArray[i] = (List_Links *) Malloc(maxArchTypes *
  355.                           sizeof(List_Links));
  356.     waitingLists[i] = (List_Links *) Malloc(maxArchTypes *
  357.                         sizeof(List_Links));
  358.     for (j = 0; j < maxArchTypes; j++) {
  359.         List_Init(&idleHostsArray[i][j]);
  360.         List_Init(&inUseArray[i][j]);
  361.         List_Init(&waitingLists[i][j]);
  362.     }
  363.     }
  364.  
  365.     /*
  366.      * Initialize statistics based on our own idea of the world.  This is
  367.      * used to ensure that things haven't changed (for example, the
  368.      * mapping of architecture types to id's).  
  369.      */
  370.     InitStats();
  371.  
  372.     
  373.     /*
  374.      * Find out the last time we heard from each host, in order to
  375.      * list downtimes for hosts that aren't currently up.  Get the stats
  376.      * saved by the last daemon.
  377.      */
  378.     RestoreCheckPoint();
  379.  
  380.     period.seconds = global_CheckpointInterval;
  381.     period.microseconds = 0;
  382.     Fs_TimeoutHandlerDestroy(migd_TimeoutToken);
  383.     migd_TimeoutToken = Fs_TimeoutHandlerCreate(period, TRUE, SaveCheckPoint,
  384.                         (ClientData) NULL);
  385.  
  386.     return (0);
  387. }
  388.  
  389.  
  390. /*
  391.  *----------------------------------------------------------------------
  392.  *
  393.  * InitStats --
  394.  *
  395.  *    Initialize structures relating to statistics.  This is called
  396.  *     at startup, if an error occurs reading the last checkpoint, or
  397.  *    via an ioctl.
  398.  *
  399.  * Results:
  400.  *    None.
  401.  *
  402.  * Side effects:
  403.  *    The statistics are zeroed, and a few fields are set.
  404.  *
  405.  *----------------------------------------------------------------------
  406.  */
  407.  
  408. static void
  409. InitStats()
  410. {
  411.     int i;
  412.     
  413.     bzero((char *) &global_Stats, sizeof(global_Stats));
  414.     global_Stats.version = migd_Version;
  415.     global_Stats.checkpointInterval = global_CheckpointInterval;
  416.     global_Stats.firstRun = time(0);
  417.     global_Stats.restarts = 1;
  418.     for (i = 0; i < maxArchTypes && i < MIG_MAX_ARCH_TYPES &&
  419.      archTypesArray[i] != (char *) NULL; i++) {
  420.     strncpy(global_Stats.archStats[i].arch, archTypesArray[i],
  421.         MIG_MAX_ARCH_LEN);
  422.     }
  423.     global_Stats.maxArchs = i;
  424.  
  425.     /*
  426.      * All other fields are zero.
  427.      */
  428. }
  429.  
  430. /*
  431.  *----------------------------------------------------------------------
  432.  *
  433.  * CreateMigdRecord --
  434.  *
  435.  *    Allocate and initialize a Migd_Info record given a Host_Entry
  436.  *    record.
  437.  *
  438.  * Results:
  439.  *    None.
  440.  *
  441.  * Side effects:
  442.  *    Allocates memory.  May create a new archType.  May increase
  443.  *    count of maximum known hostID.
  444.  *
  445.  *----------------------------------------------------------------------
  446.  */
  447.  
  448. static void
  449. CreateMigdRecord(hostPtr)
  450.     Host_Entry *hostPtr;
  451. {
  452.     int archType;
  453.     int host;
  454.     Migd_Info *migdPtr;
  455.     int i;
  456.     char *hp;
  457.     int nameLen;
  458.  
  459.     host = hostPtr->id;
  460.     if (host <= 0) {
  461.     SYSLOG1(LOG_ERR, "invalid host ID from Host_Next: %d.\n",
  462.            host);
  463.     return;
  464.     } else if (host > maxHosts) {
  465.     Migd_Info **newHostArray;
  466.  
  467.     /*
  468.      * Exceeded bounds of array.  Make it double the highest
  469.      * host known and continue.
  470.      */
  471.     SYSLOG2(LOG_WARNING,
  472.            "Host identifier (%d) exceeded maximum host ID (%d).  Need to recompile program\n.",
  473.            host,
  474.            maxHosts);
  475.     newHostArray = (Migd_Info **) Malloc(sizeof(Migd_Info *) *
  476.                          (host * 2 + 1));
  477.     bcopy((char *) migInfoArray, (char *) newHostArray,
  478.           sizeof(Migd_Info *) * (maxHosts + 1));
  479.     bzero((char *) &newHostArray[maxHosts], sizeof(Migd_Info *) *
  480.           (host  + 1));
  481.     free((char *) migInfoArray);
  482.     migInfoArray = newHostArray;
  483.     maxHosts = host * 2;
  484.     }
  485.         
  486.     for (i = 0; i < maxArchTypes; i++) {
  487.     if (archTypesArray[i] == (char *) NULL) {
  488.         archTypesArray[i] = Malloc(strlen(hostPtr->machType) + 1);
  489.         strcpy(archTypesArray[i], hostPtr->machType);
  490.         archType = i;
  491.         break;
  492.     }
  493.     if (strcmp(hostPtr->machType, archTypesArray[i]) == 0) {
  494.         archType = i;
  495.         break;
  496.     }
  497.     }
  498.     if (i == maxArchTypes) {
  499.     char **newArray;
  500.     /*
  501.      * Exceeded bounds of array.  Double its size and continue.
  502.      */
  503.     SYSLOG0(LOG_WARNING,
  504.            "Too many architecture types -- should recompile program\n.");
  505.     newArray = (char **) Malloc(sizeof(char *) * maxArchTypes * 2);
  506.     bcopy((char *) archTypesArray, (char *) newArray,
  507.           sizeof(char *) * maxArchTypes);
  508.     bzero((char *) &newArray[maxArchTypes], sizeof(char *) *
  509.           maxArchTypes);
  510.     free((char *) archTypesArray);
  511.     archTypesArray = newArray;
  512.     archTypesArray[maxArchTypes] =
  513.         Malloc(strlen(hostPtr->machType) + 1);
  514.     strcpy(archTypesArray[maxArchTypes], hostPtr->machType);
  515.     archType = maxArchTypes;
  516.     maxArchTypes *= 2;
  517.     }
  518.  
  519.     /*
  520.      * Allocate and initialize a record for this host.  We assume
  521.      * it is down until we hear from it.
  522.      */
  523.     migdPtr = mnew(Migd_Info);
  524.     bzero((char *) migdPtr, sizeof(Migd_Info));
  525.     migdPtr->archType = archType;
  526.     migdPtr->info.state = MIG_HOST_DOWN;
  527.     hostCounts[archType][MIG_HOST_DOWN]++;
  528.     migdPtr->info.hostID = host;
  529.     if (host > maxKnownHost) {
  530.     maxKnownHost = host;
  531.     }
  532.     migdPtr->lastHostAssigned = -1;
  533.     List_Init(&migdPtr->links);
  534.     List_Init(&migdPtr->clientList);
  535.  
  536.     for (hp = hostPtr->name, nameLen = 0; *hp != '\0' && *hp != '.'; hp++,
  537.      nameLen++) {
  538.     }
  539.     migdPtr->name = Malloc(nameLen + 1);
  540.     bcopy(hostPtr->name, migdPtr->name, nameLen);
  541.     migdPtr->name[nameLen] = '\0';
  542.  
  543.     migInfoArray[host] = migdPtr;
  544.     
  545. }
  546.  
  547.  
  548. /*
  549.  *----------------------------------------------------------------------
  550.  *
  551.  * Global_End --
  552.  *
  553.  *    Terminate service of the master end of the pdev.
  554.  *
  555.  * Results:
  556.  *    None.
  557.  *
  558.  * Side effects:
  559.  *    The pdev is removed and closed.
  560.  *
  561.  *----------------------------------------------------------------------
  562.  */
  563.  
  564. void
  565. Global_End()
  566. {
  567.     if (global_Debug > 0) {
  568.     PRINT_PID;
  569.     fprintf(stderr, "Global_End -\n");
  570.     }
  571.  
  572.     
  573.     
  574.     MigPdev_End();
  575.     if (global_Debug > 0) {
  576.     PRINT_PID;
  577.     fprintf(stderr, "Global_End - exiting.\n");
  578.     }
  579.     (void) unlink(MIGD_LOCK_FILE);
  580.     DATE();
  581.     exit(0);
  582.  
  583. }
  584.  
  585.  
  586. /*
  587.  *----------------------------------------------------------------------
  588.  *
  589.  * Global_Quit --
  590.  *
  591.  *    Called at exit.  If any outstanding daemons exist, it tells
  592.  *    them to quit as well.  This is normally done because of a
  593.  *    signal such as SIGINT (i.e., more for debugging than
  594.  *    production use).  Note, it uses the sprite signal numbering
  595.  *    scheme because it bypasses the compatibility library.  If
  596.  *    there are outstanding clients it doesn't actually exit itself;
  597.  *    instead the daemon waits until the last client exits (or
  598.  *    another signal occurs).
  599.  *
  600.  * Results:
  601.  *    None.
  602.  *
  603.  * Side effects:
  604.  *      Clients are signalled and should exit ASAP.
  605.  *
  606.  *----------------------------------------------------------------------
  607.  */
  608.  
  609. void
  610. Global_Quit()
  611. {
  612.     if (hostsUp == 0) {
  613.     Global_End();
  614.     } else {
  615.     MigPdev_SignalClients(SIG_TERM);
  616.     }
  617. }
  618.  
  619. /*
  620.  *----------------------------------------------------------------------
  621.  *
  622.  * Global_GetLoadInfo --
  623.  *
  624.  *    Get the information for one or more hosts and put it in a buffer.
  625.  *    This routine is called via a callback during an ioctl.  
  626.  *
  627.  * Results:
  628.  *    The size of the output buffer used is returned in *outBufSizePtr.
  629.  *    On error, a non-zero error status is returned.
  630.  *
  631.  * Side effects:
  632.  *    None.
  633.  *
  634.  *----------------------------------------------------------------------
  635.  */
  636.  
  637. /* ARGSUSED */
  638. int
  639. Global_GetLoadInfo(cltPtr, command, inBuffer, inBufSize, outBuffer,
  640.            outBufSizePtr)
  641.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  642.                    the request. */
  643.     int command;        /* Ignored. */
  644.     char *inBuffer;        /* Buffer to get arguments from. */
  645.     int inBufSize;        /* Size of the input buffer. */
  646.     char *outBuffer;        /* Buffer to place results. */
  647.     int *outBufSizePtr;        /* Size of the output buffer, modified with
  648.                    amount used. */
  649. {
  650.     Mig_InfoRequest *infoReqPtr;/* Request from client. */
  651.     int i;            /* Counter. */
  652.     int total;            /* Number of entries found. */
  653.     int firstHost;        /* Sprite ID of first host to return info
  654.                    for. */
  655.     int numRecs;        /* Maximum number of entries to return. */
  656.     char *bufPtr;        /* Pointer into output buffer. */
  657.     Mig_Info *infoPtr;        /* Pointer into output buffer. */
  658.     int *totalPtr;        /* Pointer into output buffer. */
  659.     
  660.     if (global_Debug > 2) {
  661.     PRINT_PID;
  662.     fprintf(stderr,
  663.            "Global_GetLoadInfo: called from process %x\n",
  664.            cltPtr->processID);
  665.     }
  666.     if (inBufSize != sizeof(Mig_InfoRequest)) {
  667.     if (global_Debug > 0) {
  668.         SYSLOG2(LOG_WARNING,
  669.            "Global_GetLoadInfo: bad input buffer size (%d) from process %x\n",
  670.            inBufSize, cltPtr->processID);
  671.     }
  672.     return(EINVAL);
  673.     }
  674.     global_Stats.getLoadRequests++;
  675.     infoReqPtr = (Mig_InfoRequest *) inBuffer;
  676.     firstHost = infoReqPtr->firstHost;
  677.     numRecs = infoReqPtr->numRecs;
  678.     if (firstHost <= 0 ||
  679.     *outBufSizePtr < (sizeof(int) + numRecs * sizeof(Mig_Info))) {
  680.     if (global_Debug > 0) {
  681.         SYSLOG2(LOG_WARNING,
  682.            "Global_GetLoadInfo: bad firstHost argument (%d) or output  buffer size (%d)\n",
  683.            firstHost,*outBufSizePtr);
  684.         SYSLOG2(LOG_WARNING,
  685.            "\tfor %d records, from process %x\n", numRecs,
  686.             cltPtr->processID);
  687.     }
  688.     return(EINVAL);
  689.     }
  690.  
  691.     if (global_Debug > 2) {
  692.     PRINT_PID;
  693.     fprintf(stderr,
  694.            "Global_GetLoadInfo: requested %d hosts starting at %d\n",
  695.            numRecs, firstHost);
  696.     }
  697.     bufPtr = outBuffer;
  698.     totalPtr = (int *) bufPtr;
  699.     bufPtr += 2 * sizeof(int);
  700.     infoPtr = (Mig_Info *) bufPtr;
  701.     for (i = firstHost, total = 0; i <= maxKnownHost && total < numRecs;
  702.      i++) { 
  703.     if (migInfoArray[i] != (Migd_Info *) NULL &&
  704.         migInfoArray[i]->info.loadVec.timestamp != 0) {
  705.         bcopy((char *) &migInfoArray[i]->info, (char *) infoPtr,
  706.           sizeof(Mig_Info));
  707.         infoPtr++;
  708.         total++;
  709.         if (global_Debug > 4) {
  710.         PRINT_PID;
  711.         fprintf(stderr,
  712.                "Global_GetLoadInfo: entry %d is %s\n",
  713.                total, migInfoArray[i]->name);
  714.         }
  715.     }
  716.     }
  717.     *totalPtr = total;
  718.     *outBufSizePtr = 2 * sizeof(int) + total * sizeof(Mig_Info);
  719.     if (global_Debug > 2) {
  720.     PRINT_PID;
  721.     fprintf(stderr,
  722.            "Global_GetLoadInfo: returning %d bytes for %d entries.\n",
  723.            *outBufSizePtr, total);
  724.     }
  725.     return(0);
  726.     
  727. }
  728.  
  729.  
  730. /*
  731.  *----------------------------------------------------------------------
  732.  *
  733.  * Global_GetIdle --
  734.  *
  735.  *    Get one or more idle hosts and put their IDs in a buffer.
  736.  *    This routine is called via a callback during an ioctl.  
  737.  *
  738.  * Results:
  739.  *    The size of the output buffer used is returned in *outBufSizePtr.
  740.  *    On error, a non-zero error status is returned.
  741.  *
  742.  * Side effects:
  743.  *    The hosts obtained may be shuffled to another queue.
  744.  *    Allocates various structures.
  745.  *
  746.  *----------------------------------------------------------------------
  747.  */
  748.  
  749. /* ARGSUSED */
  750. int
  751. Global_GetIdle(cltPtr, command, inBuffer, inBufSize, outBuffer,
  752.            outBufSizePtr)
  753.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  754.                    the request. */
  755.     int command;        /* Ignored. */
  756.     char *inBuffer;        /* Buffer to get arguments from. */
  757.     int inBufSize;        /* Size of the input buffer. */
  758.     char *outBuffer;        /* Buffer to place results. */
  759.     int *outBufSizePtr;        /* Size of the output buffer, modified with
  760.                    amount used. */
  761. {
  762.     Mig_IdleRequest *idleReqPtr;/* Request from client. */
  763.     int *outPtr;        /* Pointer into output buffer. */
  764.     int total;            /* Number of entries found. */
  765.     int numHosts;        /* Maximum number of host IDs to return. */
  766.     int priority;        /* Priority of process. */
  767.     int tryPrio;        /* Temporary variable for priority. */
  768.     List_Links *idleList;    /* Pointer to header of a list of idle
  769.                    hosts. */
  770.     List_Links *listPtr;    /* Current element in list. */
  771.     List_Links *nextPtr;    /* Next element in list. */
  772.     int    archType;        /* Numeric identifier for client
  773.                    architecture. */
  774.     int    migVersion;        /* Migration version of requester's host. */
  775.     Migd_Info *migdPtr;        /* Pointer to internal form of info for a
  776.                    host. */
  777.     Migd_Info *reqMigdPtr;    /* Pointer to info for requester's machine. */
  778.     Mig_Info *infoPtr;        /* Pointer to external form of info for
  779.                    host. */
  780.     RequestInfo *reqPtr;    /* Pointer to info for a request. */
  781.     Mig_ArchStats *archPtr;    /* For statistics. */
  782.     int retry;            /* Used for looping on requests. */
  783.  
  784.     if (inBufSize != sizeof(Mig_IdleRequest)) {
  785.     if (global_Debug > 0) {
  786.         SYSLOG2(LOG_WARNING,
  787.            "Global_GetIdle: bad input buffer size (%d) from process %x\n",
  788.            inBufSize, cltPtr->processID);
  789.     }
  790.     return(EINVAL);
  791.     }
  792.     idleReqPtr = (Mig_IdleRequest *) inBuffer;
  793.     numHosts = idleReqPtr->numHosts;
  794.  
  795.  
  796.     reqMigdPtr = migInfoArray[cltPtr->host];
  797.     if (reqMigdPtr == (Migd_Info *) NULL ||
  798.     reqMigdPtr->info.state == MIG_HOST_DOWN) {
  799.     if (global_Debug > 0) {
  800.         char buf[10];
  801.         SYSLOG1(LOG_WARNING,
  802.            "Global_GetIdle: no daemon for requester's host (%s).\n",
  803.             reqMigdPtr == (Migd_Info *) NULL ?
  804.             sprintf(buf, "%d", cltPtr->host) : reqMigdPtr->name);
  805.     }
  806.     return(ENOTCONN);
  807.     }
  808.     
  809.     if (global_Debug > 1) {
  810.     PRINT_PID;
  811.     fprintf(stderr,
  812.            "Global_GetIdle: request for %d hosts from process %x on %s\n",
  813.            numHosts, cltPtr->processID, reqMigdPtr->name);
  814.     }
  815.  
  816.     priority = idleReqPtr->priority;
  817.     if (numHosts <= 0 ||
  818.     *outBufSizePtr < (1 + numHosts) * sizeof(int) ||
  819.     priority < MIG_LOW_PRIORITY ||
  820.     priority > MIG_HIGH_PRIORITY) {
  821.     if (global_Debug > 0) {
  822.         PRINT_PID;
  823.         fprintf(stderr,
  824.            "Global_GetIdle: bad number of hosts requested (%d), priority (%d), or output buffer size (%d) from process %x\n",
  825.            numHosts, priority, *outBufSizePtr, cltPtr->processID);
  826.     }
  827.     return(EINVAL);
  828.     }
  829.  
  830.     archType = reqMigdPtr->archType;
  831.     migVersion = reqMigdPtr->info.migVersion;
  832.  
  833.     if (migd_DoStats) {
  834.     archPtr = &global_Stats.archStats[archType];
  835.     if (cltPtr->numRequested == 0) {
  836.         if (global_Debug > 2) {
  837.         PRINT_PID;
  838.         fprintf(stderr,
  839.                "Global_GetIdle: first request from process %x.\n",
  840.                cltPtr->processID);
  841.         }
  842.         archPtr->numClients++;
  843.     }
  844.     cltPtr->numRequested += numHosts;
  845.     if (cltPtr->numInUse + numHosts > cltPtr->maxRequests) {
  846.         cltPtr->maxRequests = cltPtr->numInUse + numHosts;
  847.     }
  848.     global_Stats.totalRequests += numHosts;
  849.     }
  850.  
  851.     /*
  852.      * Try to assign as many hosts as requested.  (At some point we
  853.      * might put in some sort of fairness constraints here.)  We
  854.      * look at hosts that are available for the given priority or lower,
  855.      * meaning that a normal priority job can run on a machine that's
  856.      * already being used for a background job but not vice-versa.
  857.      */
  858.  
  859.     outPtr = (int *) (outBuffer + sizeof(int));
  860.  
  861.     total = 0;
  862.     retry = 1;
  863.     while (retry) {
  864.  
  865.     tryPrio = MIG_LOW_PRIORITY;
  866.     while (total < numHosts && tryPrio <= priority) {
  867.         idleList = &idleHostsArray[tryPrio][archType];
  868.         nextPtr = List_First(idleList);
  869.         while (total < numHosts && !List_IsAtEnd(idleList, nextPtr)) {
  870.         listPtr = nextPtr;
  871.         nextPtr = List_Next(nextPtr);
  872.         migdPtr = (Migd_Info *) listPtr;
  873.         if (global_Debug > 3) {
  874.             PRINT_PID;
  875.             fprintf(stderr, "Examining %s.\n",
  876.                 migdPtr->name);
  877.         }
  878.         if (migdPtr->info.hostID == idleReqPtr->virtHost ||
  879.             migdPtr->info.hostID == cltPtr->host) {
  880.             if (global_Debug > 3) {
  881.             PRINT_PID;
  882.             fprintf(stderr, "Skipping over %s.\n",
  883.                 migdPtr->name);
  884.             }
  885.             continue;
  886.         }
  887.         if (migdPtr->info.migVersion != migVersion) {
  888.             if (global_Debug > 3) {
  889.             PRINT_PID;
  890.             fprintf(stderr,
  891.                 "Migration version mismatch: %s version %d, %s version %d.\n",
  892.                 migdPtr->name, migdPtr->info.migVersion,
  893.                 reqMigdPtr->name, migVersion);
  894.             }
  895.             continue;
  896.         }
  897.         infoPtr = (Mig_Info *) &migdPtr->info;
  898.         infoPtr->foreign[priority]++;
  899.         if (infoPtr->foreign[priority] >= infoPtr->maxProcs) {
  900.             /*
  901.              * Used up all the processors on this host for processes
  902.              * of this type, so put the host on the queue for
  903.              * the next higher priority.
  904.              */
  905.             List_Remove(listPtr);
  906.             hostCounts[archType][infoPtr->state]--;
  907.             if (priority < MIG_HIGH_PRIORITY) {
  908.             List_Insert(listPtr,
  909.                     LIST_ATREAR(&idleHostsArray
  910.                         [priority + 1][archType]));
  911.             infoPtr->state = MIG_HOST_PART_USED;
  912.             } else {
  913.             infoPtr->state = MIG_HOST_FULL;
  914.             }
  915.             hostCounts[archType][infoPtr->state]++;
  916.         }
  917.         /*
  918.          * Allocate a new request info structure and set it up
  919.          * so we can find this request via the host's record or via the
  920.          * client process.  Only chain it to the client process if
  921.          * it isn't an "agent" request, since we reclaim hosts on the
  922.          * client's chain of requests when the connection is closed.
  923.          *
  924.          * XXX We'd like to assign multiple processors in a single shot
  925.          * here...
  926.          */
  927.         reqPtr = mnew(RequestInfo);
  928.         reqPtr->priority = priority;
  929.         reqPtr->migdPtr = migdPtr;
  930.         reqPtr->flags = idleReqPtr->flags;
  931.         reqPtr->idleTime = migdPtr->info.loadVec.noInput;
  932.         reqPtr->numProcessors = 1;
  933.         if (! (reqPtr->flags & MIG_PROC_AGENT)) {
  934.             reqPtr->client.cltPtr = cltPtr;
  935.             List_InitElement(&reqPtr->nextClientRequest);
  936.             List_Insert(&reqPtr->nextClientRequest,
  937.                 LIST_ATREAR(&cltPtr->currentRequests));
  938.         } else {
  939.             reqPtr->client.processID = cltPtr->processID;
  940.             migdPtr->flags |= MIGD_CHECK_COUNT;
  941.         }
  942.         migdPtr->flags &= ~MIGD_WAS_EMPTY;
  943.         if (migd_DoStats) {
  944.             int noInput;
  945.  
  946.             global_Stats.totalObtained++;
  947.             noInput = (infoPtr->loadVec.noInput + 30) / 60 ;
  948.             reqPtr->timestamp = time(0);
  949.             reqPtr->idleTime = noInput;
  950.             ADD_WITH_OVERFLOW(archPtr->counters.hostIdleObtained, noInput);
  951.             ADD_WITH_OVERFLOW(archPtr->squared.hostIdleObtained,
  952.                       noInput * noInput);
  953.             /*
  954.              * Is this host being assigned to the last host that was
  955.              * using it?
  956.              */
  957.             if (migdPtr->lastHostAssigned == cltPtr->host) {
  958.             if (global_Debug > 4) {
  959.                 PRINT_PID;
  960.                 fprintf(stderr, "\t** Repeat assignment:\n");
  961.             }
  962.             global_Stats.numRepeatAssignments++;
  963.             } else if (migdPtr->lastHostAssigned == -1) {
  964.             if (global_Debug > 4) {
  965.                 PRINT_PID;
  966.                 fprintf(stderr, "\t** First assignment to host:\n");
  967.             }
  968.             global_Stats.numFirstAssignments++;
  969.             }
  970.             migdPtr->lastHostAssigned = cltPtr->host;
  971.  
  972.             if (cltPtr->host == lastRequestHost) {
  973.             if (global_Debug > 4) {
  974.                 PRINT_PID;
  975.                 fprintf(stderr, "\t** Repeat requesting host:\n");
  976.             }
  977.             global_Stats.numRepeatRequests++;
  978.             }
  979.             lastRequestHost = cltPtr->host;
  980.         }
  981.  
  982.         List_InitElement(&reqPtr->nextHostRequest);
  983.         List_Insert(&reqPtr->nextHostRequest,
  984.                 LIST_ATREAR(&migdPtr->clientList));
  985.  
  986.         List_InitElement(&reqPtr->nextInUse);
  987.         List_Insert(&reqPtr->nextInUse,
  988.                 LIST_ATREAR(&inUseArray[priority + 1][archType]));
  989.         
  990.         if (global_Debug > 2) {
  991.             PRINT_PID;
  992.             fprintf(stderr, "\t** Assigning %s to process %x.\n",
  993.                 migdPtr->name, cltPtr->processID);
  994.         }
  995.         total++;
  996.         *outPtr = infoPtr->hostID;
  997.         outPtr++;
  998.         }
  999.         tryPrio++;
  1000.     }
  1001.     if (total < numHosts) {
  1002.         retry = CheckFairness(cltPtr, priority);
  1003.     } else {
  1004.         retry = 0;
  1005.     }
  1006.  
  1007.     }
  1008.     if (global_Debug > 1) {
  1009.     PRINT_PID;
  1010.     fprintf(stderr, "Global_GetIdle: allocated %d hosts to process %x\n",
  1011.            total, cltPtr->processID);
  1012.     }
  1013.  
  1014.     outPtr = (int *) outBuffer;
  1015.     *outPtr = total;
  1016.     *outBufSizePtr = (total + 1) * sizeof(int);
  1017.  
  1018.     cltPtr->numInUse += total;
  1019.     if (migd_DoStats) {
  1020.     cltPtr->numObtained += total;
  1021.     if (cltPtr->numInUse > cltPtr->maxObtained) {
  1022.         cltPtr->maxObtained = cltPtr->numInUse;
  1023.     }
  1024.     }
  1025.     
  1026.     if (total < numHosts && cltPtr->waitPtr == (Migd_WaitList *) NULL) {
  1027.     List_Links *waitingList = &waitingLists[priority][archType];
  1028.     Migd_WaitList *waitPtr = mnew(Migd_WaitList);
  1029.  
  1030.     if (global_Debug > 2) {
  1031.         PRINT_PID;
  1032.         fprintf(stderr, "\t** Process %x put on waiting list.\n",
  1033.            cltPtr->processID);
  1034.     }
  1035.     List_InitElement(&waitPtr->links);
  1036.     waitPtr->cltPtr = cltPtr;
  1037.     cltPtr->waitPtr = waitPtr;
  1038.     List_Insert(&waitPtr->links, LIST_ATREAR(waitingList));
  1039.     cltPtr->denied = 1;
  1040.     }
  1041.  
  1042.  
  1043.     return(0);
  1044.     
  1045. }
  1046.  
  1047.  
  1048. /*
  1049.  *----------------------------------------------------------------------
  1050.  *
  1051.  * CheckFairness --
  1052.  *
  1053.  *    Check on how hosts are allocated to see if hosts should be
  1054.  *    reclaimed.
  1055.  *
  1056.  * Results:
  1057.  *    Returns 1 if more hosts are available, or 0 if not.
  1058.  *
  1059.  * Side effects:
  1060.  *    May send message to migration daemons to ask them to evict.
  1061.  *    Flags the owner of the processes that we kick off so that
  1062.  *    that process won't be assigned hosts anytime soon if there
  1063.  *    are other processes that want hosts.
  1064.  *
  1065.  *----------------------------------------------------------------------
  1066.  */
  1067.  
  1068. static int
  1069. CheckFairness(cltPtr, priority)
  1070.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  1071.                    the request. */
  1072.     int priority;        /* Priority of process allocated. */
  1073. {
  1074.     RequestInfo *reqPtr;
  1075.     Migd_Info *cltMigdPtr;    /* Pointer to info for requesting client's
  1076.                    machine. */
  1077.     Migd_Info *migdPtr;        /* Pointer to info for various other
  1078.                    machines. */
  1079.     int    migVersion;        /* Migration version of requester's host. */
  1080.     Migd_OpenStreamInfo *reqCltPtr; /* Client that made request we're looking
  1081.                        at. */
  1082.     RequestInfo *bestReqPtr = NULL; /* Best host we've seen so far. */
  1083.     Migd_OpenStreamInfo *bestCltPtr; /* Client using that host with this
  1084.                     priority. */
  1085.     List_Links *listPtr;    /* Pointer to chain through list. */
  1086.     int okayToUse;        /* Flag while stepping through loop. */
  1087.     int checkPrio;        /* Priority index in loop. */
  1088.  
  1089.  
  1090.     if (global_Debug > 2) {
  1091.     PRINT_PID;
  1092.     fprintf(stderr,
  1093.            "CheckFairness called: client %x priority %d.\n",
  1094.        cltPtr->processID, priority);
  1095.     }
  1096.     
  1097.  
  1098.  
  1099.     cltMigdPtr = migInfoArray[cltPtr->host];
  1100.     migVersion = cltMigdPtr->info.migVersion;
  1101.  
  1102.     /*
  1103.      * Initialize bestCltPtr to ourselves so we only look at clients
  1104.      * with more hosts in use than we have.  We also fudge our count
  1105.      * to ensure that we don't steal from someone with 2 hosts to give a
  1106.      * host to someone with one host.  
  1107.      */
  1108.     bestCltPtr = cltPtr;
  1109.     cltPtr->numInUse++;
  1110.     
  1111.     LIST_FORALL(&inUseArray[priority + 1][cltMigdPtr->archType], listPtr) {
  1112.     reqPtr = NEXT_HOST_IN_USE_TO_INFO(listPtr);
  1113.     if (reqPtr->flags & (MIG_PROC_AGENT)) {
  1114.         if (global_Debug > 3) {
  1115.         PRINT_PID;
  1116.         fprintf(stderr,
  1117.                "CheckFairness skipping request on host %d, flags 0x%x.\n",
  1118.             reqPtr->migdPtr->info.hostID, reqPtr->flags);
  1119.         }
  1120.         continue;
  1121.     }
  1122.     reqCltPtr = reqPtr->client.cltPtr;
  1123.     migdPtr = migInfoArray[reqCltPtr->host];
  1124.     if (migdPtr->info.migVersion != migVersion) {
  1125.         if (global_Debug > 3) {
  1126.         PRINT_PID;
  1127.         fprintf(stderr,
  1128.                "CheckFairness skipping request on host %d, migration version %d.\n",
  1129.             reqPtr->migdPtr->info.hostID, migdPtr->info.migVersion);
  1130.         }
  1131.         continue;
  1132.     }
  1133.     /*
  1134.      * We want to see if the host that was already is assigned is the
  1135.      * same as the host making the new request, in which case there's
  1136.      * no point in reclaiming it since the new requester won't use it.
  1137.      */
  1138.     if (reqPtr->migdPtr->info.hostID == cltPtr->host) {
  1139.         if (global_Debug > 3) {
  1140.         PRINT_PID;
  1141.         fprintf(stderr,
  1142.                "CheckFairness skipping request using host %d assigned to process %x: same host as new requester.\n",
  1143.             reqPtr->migdPtr->info.hostID, reqCltPtr->processID);
  1144.         }
  1145.         continue;
  1146.     }
  1147.     /*
  1148.      * Only reclaim a host if it's assigned to only one process, at
  1149.      * least for now.  Otherwise it will evict a process and we'll
  1150.      * never notify the process's agent.  We check for a count of 1
  1151.      * at the priority we're evicting and 0 elsewhere.
  1152.      */
  1153.     for (okayToUse = 1, checkPrio = MIG_LOW_PRIORITY;
  1154.          okayToUse && checkPrio <= MIG_HIGH_PRIORITY;
  1155.          checkPrio++) {
  1156.         if (reqPtr->migdPtr->info.foreign[checkPrio] >
  1157.         ((priority == checkPrio) ? 1 : 0)) {
  1158.         if (global_Debug > 1) {
  1159.             PRINT_PID;
  1160.             fprintf(stderr,
  1161.                 "CheckFairness skipping request using host %d because more than one client assigned to this host.\n",
  1162.                 reqPtr->migdPtr->info.hostID);
  1163.         }
  1164.         okayToUse = 0;
  1165.         }
  1166.     }
  1167.     if (!okayToUse) {
  1168.         continue;
  1169.     }
  1170.     if (global_Debug > 5) {
  1171.         PRINT_PID;
  1172.         fprintf(stderr,
  1173.            "CheckFairness comparing client %x (%d hosts) to client %x (%d hosts).\n",
  1174.             reqCltPtr->processID, reqCltPtr->numInUse,
  1175.             bestCltPtr->processID, bestCltPtr->numInUse);
  1176.     }
  1177.     if (reqCltPtr->numInUse > bestCltPtr->numInUse) {
  1178.         if (global_Debug > 4) {
  1179.         PRINT_PID;
  1180.         fprintf(stderr,
  1181.                "CheckFairness choosing client %x using %d hosts, this one %d.\n",
  1182.            reqCltPtr->processID, reqCltPtr->numInUse,
  1183.             bestCltPtr->numInUse);
  1184.         }
  1185.         bestCltPtr = reqCltPtr;
  1186.         bestReqPtr = reqPtr;
  1187.     } else if (reqCltPtr == bestCltPtr) {
  1188.         bestReqPtr = reqPtr;
  1189.         if (global_Debug > 4) {
  1190.         PRINT_PID;
  1191.         fprintf(stderr,
  1192.                "CheckFairness changing to evict client %x on host %d.\n",
  1193.            reqCltPtr->processID, reqPtr->migdPtr->info.hostID);
  1194.         }
  1195.     }
  1196.     }
  1197.     /*
  1198.      * Undo the fudge factor.
  1199.      */
  1200.     cltPtr->numInUse--;
  1201.     if (bestCltPtr != cltPtr) {
  1202.     if (global_Debug > 1) {
  1203.         PRINT_PID;
  1204.         fprintf(stderr,
  1205.            "CheckFairness evicting processes on host %s.\n",
  1206.             bestReqPtr->migdPtr->name);
  1207.     }
  1208.     TellClient(bestReqPtr->migdPtr->cltPtr, 0);
  1209.     RevokePermission(bestReqPtr, REVOKE_STOLEN);
  1210.     List_Remove(&bestReqPtr->nextHostRequest);
  1211.     if (HostIsIdle(bestReqPtr->migdPtr)) {
  1212.         List_Remove((List_Links *) bestReqPtr->migdPtr);
  1213.     }
  1214.     InsertIdle(bestReqPtr->migdPtr);
  1215.     free(bestReqPtr);
  1216.     return(1);
  1217.     }
  1218.     return(0);
  1219. }
  1220.  
  1221.  
  1222. /*
  1223.  *----------------------------------------------------------------------
  1224.  *
  1225.  * Global_DoneIoctl --
  1226.  *
  1227.  *    Note that a process is through with one or more hosts.
  1228.  *    This routine is called via a callback during an ioctl.
  1229.  *    It's really just a stub to call a regular routine without
  1230.  *     the extra args.
  1231.  *
  1232.  * Results:
  1233.  *    On error, a non-zero error status is returned, else 0.
  1234.  *
  1235.  * Side effects:
  1236.  *    The hosts are put back on appropriate queues.
  1237.  *
  1238.  *----------------------------------------------------------------------
  1239.  */
  1240.  
  1241. /* ARGSUSED */
  1242. int
  1243. Global_DoneIoctl(cltPtr, command, inBuffer, inBufSize, outBuffer,
  1244.            outBufSizePtr)
  1245.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  1246.                    the request. */
  1247.     int command;        /* Ignored. */
  1248.     char *inBuffer;        /* Buffer to get arguments from. */
  1249.     int inBufSize;        /* Size of the input buffer. */
  1250.     char *outBuffer;        /* Buffer to place results, not used. */
  1251.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  1252. {
  1253.     int *hostPtr;        /* Pointer into input buffer. */
  1254.     int i;            /* Counter. */
  1255.     int numArgs;        /* Number of args (host IDs). */
  1256.     int status;            /* Status from subroutine calls. */
  1257.  
  1258.     if ((inBufSize % sizeof(int)) != 0 || inBufSize <= 0) {
  1259.     if (global_Debug > 0) {
  1260.         SYSLOG2(LOG_WARNING,
  1261.            "Global_DoneIoctl: bad input buffer size (%d) from process %x\n",
  1262.            inBufSize, cltPtr->processID);
  1263.     }
  1264.     return(EINVAL);
  1265.     }
  1266.     numArgs = inBufSize / sizeof(int);
  1267.     hostPtr = (int *) inBuffer;
  1268.     for (i = 0; i < numArgs; i++, hostPtr++) {
  1269.     status = Global_Done(cltPtr, *hostPtr, 0);
  1270.     if (status != 0) {
  1271.         return(status);
  1272.     }
  1273.     }
  1274.     return(0);
  1275. }
  1276.  
  1277.  
  1278.  
  1279. /*
  1280.  *----------------------------------------------------------------------
  1281.  *
  1282.  * Global_Done --
  1283.  *
  1284.  *    Note that a process is through with one or more hosts.
  1285.  *    Takes a single host specification, which may be MIG_ALL_HOSTS
  1286.  *    to indicate that all hosts are to be returned.
  1287.  *
  1288.  * Results:
  1289.  *    Returns 0.
  1290.  *
  1291.  * Side effects:
  1292.  *    The hosts may be moved to a different queue.  Memory is freed.
  1293.  *
  1294.  *----------------------------------------------------------------------
  1295.  */
  1296.  
  1297. int
  1298. Global_Done(cltPtr, host, exiting)
  1299.     Migd_OpenStreamInfo *cltPtr;/* Information about the client involved. */
  1300.     int host;            /* Host specification. */
  1301.     int exiting;        /* Whether this call is because the process
  1302.                    is exiting. */
  1303. {
  1304.     int priority;        /* Priority of process. */
  1305.     List_Links *cltList;    /* Pointer to header of client's list of
  1306.                    hosts it's using. */
  1307.     List_Links *cltListPtr;    /* Pointer into list. */
  1308.     List_Links *listPtr;    /* Temporary var: pointer to element of list. */
  1309.     List_Links *nextPtr;    /* For iterations, pointer to next element
  1310.                    of list. */
  1311.     int numReturned = 0;    /* Number of hosts returned. */
  1312.     Migd_Info *migdPtr;        /* Pointer to internal form of info for
  1313.                    a host. */
  1314.     Mig_Info *infoPtr;        /* Pointer to external form of info for
  1315.                    host. */
  1316.     RequestInfo *reqPtr;    /* Pointer to info for a request. */
  1317.     MessageBlock *msgPtr;    /* Pointer to message enqueued for client. */
  1318.     int returnCode = 0;        /* Value to return at end. */
  1319.     int requests;        /* Number of hosts requested, for statistics. */
  1320.     int obtained;        /* Number of hosts obtained, for statistics. */
  1321.     Mig_ArchStats *archStatsPtr;/* Pointer to per-architecture statistics. */
  1322.  
  1323.     
  1324.     if (global_Debug > 2) {
  1325.     if (host) {
  1326.         PRINT_PID;
  1327.         fprintf(stderr,
  1328.            "Global_Done: return %s to free pool for process %x\n",
  1329.            migInfoArray[host]->name, cltPtr->processID);
  1330.     } else {
  1331.         PRINT_PID;
  1332.         fprintf(stderr,
  1333.            "Global_Done: return all hosts to free pool for process %x\n",
  1334.            cltPtr->processID);
  1335.     }
  1336.     }
  1337.  
  1338.     /*
  1339.      * Check the list of hosts this client is using.
  1340.      */
  1341.  
  1342.     
  1343.     cltList = &cltPtr->currentRequests;
  1344.     if (List_IsEmpty(cltList)) {
  1345.     if (global_Debug > 2) {
  1346.         PRINT_PID;
  1347.         fprintf(stderr,
  1348.            "Global_Done: process %x has empty client list\n",
  1349.            cltPtr->processID);
  1350.     }
  1351.     goto done;
  1352.     }
  1353.     
  1354.  
  1355.     
  1356.     cltListPtr = List_First(cltList);
  1357.  
  1358.     /*
  1359.      * Go through list of requests looking for this host, or for each
  1360.      * host if so specified.
  1361.      */
  1362.  
  1363.     while (!List_IsAtEnd(cltList, cltListPtr)) {
  1364.  
  1365.     reqPtr = (RequestInfo *) cltListPtr;
  1366.     migdPtr = reqPtr->migdPtr;
  1367.     infoPtr = &migdPtr->info;
  1368.     priority  = reqPtr->priority;
  1369.     if (host != MIG_ALL_HOSTS && infoPtr->hostID != host) {
  1370.         cltListPtr = List_Next(cltListPtr);
  1371.         continue;
  1372.     }
  1373.     /*
  1374.      * Found a record for a host assignment we want to remove.
  1375.      * First extract it from the client's list and from the list
  1376.      * associated with the host being used.
  1377.      */
  1378.     listPtr = List_Next(cltListPtr);
  1379.     List_Remove(cltListPtr);
  1380.     cltListPtr = listPtr;
  1381.     listPtr = &reqPtr->nextHostRequest;
  1382.     List_Remove(listPtr);
  1383.     listPtr = &reqPtr->nextInUse;
  1384.     List_Remove(listPtr);
  1385.     numReturned++;
  1386.  
  1387.     infoPtr->foreign[priority] -= reqPtr->numProcessors;
  1388.     if (infoPtr->foreign[priority] == infoPtr->maxProcs - 1) {
  1389.         /*
  1390.          * Now have a free processor on this host for processes
  1391.          * of this type, so put the host on the queue for
  1392.          * this priority.
  1393.          */
  1394.         if (HostIsIdle(migdPtr)) {
  1395.         List_Remove((List_Links *) migdPtr);
  1396.         }
  1397.         if (infoPtr->loadVec.allowMigration) {
  1398.         InsertIdle(migdPtr);
  1399.         } else {
  1400.         migdPtr->info.state = MIG_HOST_ACTIVE;
  1401.         }
  1402.     } else if (global_Debug > 1) {
  1403.         PRINT_PID;
  1404.         fprintf(stderr,
  1405.            "Foreign count %d of priority %d on %s not just below maxProcs (%d).\n",
  1406.            infoPtr->foreign[priority], priority, migdPtr->name,
  1407.            infoPtr->maxProcs);
  1408.     }
  1409.     if (migd_DoStats) {
  1410.         int curTime = time(0);
  1411.         int timeUsed = curTime - reqPtr->timestamp;
  1412.         global_Stats.archStats[migdPtr->archType].counters.timeUsed +=
  1413.         timeUsed;
  1414.         global_Stats.archStats[migdPtr->archType].squared.timeUsed +=
  1415.         timeUsed * timeUsed;
  1416.     }
  1417.     
  1418.     free ((char *) reqPtr);
  1419.     }
  1420.  
  1421.     done:
  1422.     if (exiting) {
  1423.     /*
  1424.      * Clean up after the process -- get rid of messages, and the message
  1425.      * list.  Record statistics.
  1426.      */
  1427.     listPtr = List_First(&cltPtr->messages);
  1428.     while (!List_IsAtEnd(&cltPtr->messages, listPtr)) {
  1429.         nextPtr = List_Next(listPtr);
  1430.         msgPtr = (MessageBlock *) listPtr;
  1431.         if (msgPtr->msg == host || host == MIG_ALL_HOSTS) {
  1432.         List_Remove(listPtr);
  1433.         free((char *) listPtr);
  1434.         }
  1435.         listPtr = nextPtr;
  1436.     }
  1437.     if (List_IsEmpty(&cltPtr->messages)) {
  1438.         cltPtr->defaultSelBits &= ~FS_READ;
  1439.     }
  1440.  
  1441.     if (cltPtr->waitPtr != (Migd_WaitList *) NULL) {
  1442.         List_Remove((List_Links *) cltPtr->waitPtr);
  1443.         free((char *) cltPtr->waitPtr);
  1444.         cltPtr->waitPtr = (Migd_WaitList *) NULL;
  1445.     }
  1446.  
  1447.     /*
  1448.      * Manage statistics.  We only count processes that have ever
  1449.      * requested hosts, and only when they close their pdev.
  1450.      */
  1451.     if (migd_DoStats && cltPtr->numRequested > 0) {
  1452.         archStatsPtr = &global_Stats.archStats
  1453.         [migInfoArray[cltPtr->host]->archType];
  1454. #ifndef min
  1455. #define min(a, b) (((a) < (b)) ? (a) : (b))
  1456. #endif
  1457.         requests = min(cltPtr->maxRequests, MIG_MAX_HOSTS_DIST);
  1458.         obtained = min(cltPtr->maxObtained, MIG_MAX_HOSTS_DIST);
  1459.         if (global_Debug > 3) {
  1460.         PRINT_PID;
  1461.         fprintf(stderr,
  1462.             "Global_Done: process %x had a max of %d requests, %d obtained, %d stolen.\n",
  1463.             cltPtr->processID, requests, obtained,
  1464.             cltPtr->numStolen);
  1465.         }
  1466.         if (cltPtr->denied == 0) {
  1467.         archStatsPtr->gotAll++;
  1468.         }
  1469.         archStatsPtr->requestDist[requests]++;
  1470.         archStatsPtr->obtainedDist[obtained]++;
  1471.         archStatsPtr->counters.requested += cltPtr->numRequested;
  1472.         archStatsPtr->squared.requested +=
  1473.         cltPtr->numRequested * cltPtr->numRequested;
  1474.         archStatsPtr->counters.obtained += cltPtr->numObtained;
  1475.         archStatsPtr->squared.obtained +=
  1476.         cltPtr->numObtained * cltPtr->numObtained;
  1477.         archStatsPtr->counters.evicted += cltPtr->numEvicted;
  1478.         archStatsPtr->squared.evicted +=
  1479.         cltPtr->numEvicted * cltPtr->numEvicted;
  1480.         archStatsPtr->counters.reclaimed += cltPtr->numStolen;
  1481.         archStatsPtr->squared.reclaimed +=
  1482.         cltPtr->numStolen * cltPtr->numStolen;
  1483.     }
  1484.     }
  1485.     
  1486.     if (global_Debug > 2) {
  1487.     PRINT_PID;
  1488.     fprintf(stderr, "Global_Done: returned %d hosts to pool for process %x\n",
  1489.            numReturned, cltPtr->processID);
  1490.     }
  1491.  
  1492.     if (numReturned > 0) {
  1493.     cltPtr->stoleTime = 0;
  1494.     }
  1495.     cltPtr->numInUse -= numReturned;
  1496.     
  1497.     return(returnCode);
  1498.     
  1499. }
  1500.  
  1501.  
  1502. /*
  1503.  *----------------------------------------------------------------------
  1504.  *
  1505.  * InsertIdle --
  1506.  *
  1507.  *    Add a host to the appropriate list of idle hosts, based on
  1508.  *    the priorities with available capacity.  The host must not be
  1509.  *    on any such list when this procedure is called.  
  1510.  *
  1511.  * Results:
  1512.  *    None.
  1513.  *
  1514.  * Side effects:
  1515.  *    Adds host to list, and sets it state based on whether it has
  1516.  *    any capacity already used.
  1517.  *
  1518.  *----------------------------------------------------------------------
  1519.  */
  1520.  
  1521. static void
  1522. InsertIdle(migdPtr)
  1523.     Migd_Info *migdPtr;
  1524. {
  1525.     List_Links *listPtr;
  1526.     List_Links *hdrPtr;
  1527.     int priority;
  1528.     int archType = migdPtr->archType;
  1529.     Mig_Info *infoPtr;
  1530.     Migd_Info *compPtr;
  1531.     int noInput;
  1532.     int found;
  1533.     int origState;
  1534.     
  1535.  
  1536.     WakeupWaiters(archType);
  1537.     infoPtr = &migdPtr->info;
  1538.     noInput = infoPtr->loadVec.noInput;
  1539.     origState = infoPtr->state;
  1540.     List_InitElement((List_Links *) migdPtr);
  1541.     if (List_IsEmpty(&migdPtr->clientList)) {
  1542.     /*
  1543.      * Fast path: host is totally idle, so put it in order
  1544.      * of idle time on the idle list, and before any
  1545.      * hosts with any low priority processes.
  1546.      */
  1547.     hdrPtr = &idleHostsArray[MIG_LOW_PRIORITY][archType];
  1548.     found = 0;
  1549.     LIST_FORALL(hdrPtr, listPtr) {
  1550.         compPtr = (Migd_Info *) listPtr;
  1551.         if (global_Debug > 2) {
  1552.         PRINT_PID;
  1553.         fprintf(stderr, "InsertIdle: comparing %s (%d secs) to %s (%d secs).\n",
  1554.                migdPtr->name, infoPtr->loadVec.noInput, 
  1555.                compPtr->name, compPtr->info.loadVec.noInput);
  1556.         }
  1557.         if (compPtr->info.loadVec.noInput < noInput ||
  1558.         compPtr->info.foreign[MIG_LOW_PRIORITY] > 0) {
  1559.         found = 1;
  1560.         break;
  1561.         }
  1562.     }
  1563.     if (found) {
  1564.         if (global_Debug > 2) {
  1565.         PRINT_PID;
  1566.         fprintf(stderr, "Inserting %s before %s\n",
  1567.                migdPtr->name, compPtr->name);
  1568.         }
  1569.         List_Insert((List_Links *) migdPtr, LIST_BEFORE(listPtr));
  1570.     } else {
  1571.         if (global_Debug > 2) {
  1572.         PRINT_PID;
  1573.         fprintf(stderr, "Inserting %s at end of list\n",
  1574.                migdPtr->name);
  1575.         }
  1576.         List_Insert((List_Links *) migdPtr, LIST_ATREAR(hdrPtr));
  1577.     }
  1578.     infoPtr->state = MIG_HOST_IDLE;
  1579.     goto done;
  1580.     } 
  1581.  
  1582.     /*
  1583.      * Look for the first priority that's filled up and put the process
  1584.      * on the queue for the next higher priority.  If none is filled up,
  1585.      * stick it on the end of the low-prio queue, after the hosts with
  1586.      * no foreign procs at all.
  1587.      */
  1588.  
  1589.     infoPtr->state = MIG_HOST_PART_USED;
  1590.     for (priority = MIG_HIGH_PRIORITY; priority >= MIG_LOW_PRIORITY;
  1591.      priority--) {
  1592.     if (infoPtr->foreign[priority] == infoPtr->maxProcs) {
  1593.         if (priority == MIG_HIGH_PRIORITY) {
  1594.         if (global_Debug > 1) {
  1595.             PRINT_PID;
  1596.             fprintf(stderr, "%s is actually all taken.\n",
  1597.                migdPtr->name);
  1598.         }
  1599.         infoPtr->state = MIG_HOST_FULL;
  1600.         goto done;
  1601.         } else {
  1602.         if (global_Debug > 2) {
  1603.             PRINT_PID;
  1604.             fprintf(stderr, "Inserting %s at end of priority %d\n",
  1605.                migdPtr->name, priority + 1);
  1606.         }
  1607.         List_Insert((List_Links *) migdPtr,
  1608.                 LIST_ATREAR(&idleHostsArray
  1609.                     [priority + 1][archType]));
  1610.         goto done;
  1611.         }
  1612.     }
  1613.     }
  1614.     List_Insert((List_Links *) migdPtr,
  1615.         LIST_ATREAR(&idleHostsArray[MIG_LOW_PRIORITY][archType]));
  1616.  
  1617.     done:
  1618.     /*
  1619.      * If host changed state, modify counters accordingly.
  1620.      */
  1621.     if (origState != infoPtr->state) {
  1622.     hostCounts[archType][origState]--;
  1623.     hostCounts[archType][infoPtr->state]++;
  1624.     }
  1625.     
  1626. }
  1627.  
  1628.  
  1629. /*
  1630.  *----------------------------------------------------------------------
  1631.  *
  1632.  * WakeupWaiters --
  1633.  *
  1634.  *    Check to see if anyone is waiting for an idle host.  Wake up all
  1635.  *    processes waiting for available hosts of this type, if a host is
  1636.  *    available at the appropriate priority.  Then let them ask again for
  1637.  *    an idle host using normal ioctls.
  1638.  *
  1639.  * Results:
  1640.  *    None.
  1641.  *
  1642.  * Side effects:
  1643.  *    Makes pdevs for clients readable so they know to contact us.
  1644.  *
  1645.  *----------------------------------------------------------------------
  1646.  */
  1647.  
  1648. static void
  1649. WakeupWaiters(archType)
  1650.     int archType;
  1651. {
  1652.     List_Links *waitingList;
  1653.     List_Links *listPtr;
  1654.     Migd_WaitList *waitPtr;
  1655.     Migd_OpenStreamInfo *cltPtr;
  1656.     MessageBlock *msgPtr;
  1657.     int curTime;
  1658.     int priority;
  1659.     int i;
  1660.     
  1661.  
  1662.     if (global_Debug > 2) {
  1663.     PRINT_PID;
  1664.     fprintf(stderr,
  1665.            "WakeupWaiters(%s) called.\n", archTypesArray[archType]);
  1666.     }
  1667.     curTime = time(0);
  1668.     for (priority = MIG_HIGH_PRIORITY; priority >= MIG_LOW_PRIORITY;
  1669.      priority--) {
  1670.     if (!List_IsEmpty(&idleHostsArray[priority][archType])) {
  1671.         for (i = priority; i <= MIG_HIGH_PRIORITY; i++) {
  1672.         waitingList = &waitingLists[priority][archType];
  1673.         while (!List_IsEmpty(waitingList)) {
  1674.             /*
  1675.              * For each process waiting, get rid of the info saying it's
  1676.              * waiting and instead add a message to the process.
  1677.              */
  1678.             listPtr = List_First(waitingList);
  1679.             waitPtr = (Migd_WaitList *) listPtr;
  1680.             List_Remove(listPtr);
  1681.             cltPtr = waitPtr->cltPtr;
  1682.             cltPtr->waitPtr = (Migd_WaitList *) NULL;
  1683.             if (cltPtr->stoleTime > curTime - MIGD_STOLE_WINDOW) {
  1684.             if (global_Debug > 0) {
  1685.                 PRINT_PID;
  1686.                 fprintf(stderr,
  1687.                     "\t** not telling process %x about host available, since we stole from it recently.\n",
  1688.                     cltPtr->processID);
  1689.             }
  1690.             } else {
  1691.             TellClient(cltPtr, 0);
  1692.             if (global_Debug > 0) {
  1693.                 PRINT_PID;
  1694.                 fprintf(stderr,
  1695.                     "\t** telling process %x about host available.\n",
  1696.                     cltPtr->processID);
  1697.             }
  1698.             }
  1699.             free((char *) waitPtr);
  1700.         }
  1701.         }
  1702.     }
  1703.     }
  1704. }
  1705.  
  1706.  
  1707.  
  1708.  
  1709. /*
  1710.  *----------------------------------------------------------------------
  1711.  *
  1712.  * RecordEvictions --
  1713.  *
  1714.  *    A host is evicting foreign processes.  Make sure it's marked
  1715.  *    appropriately, and clean up any state from foreign processes.
  1716.  *
  1717.  * Results:
  1718.  *    None.
  1719.  *
  1720.  * Side effects:
  1721.  *    Notifies clients of eviction [eventually].  Frees memory associated
  1722.  *    with outstanding requests for host.
  1723.  *
  1724.  *----------------------------------------------------------------------
  1725.  */
  1726.  
  1727. static void
  1728. RecordEvictions(migdPtr)
  1729.     Migd_Info *migdPtr;
  1730. {
  1731.     int down;
  1732.     List_Links *listPtr;
  1733.     RequestInfo *reqPtr;
  1734.     Migd_OpenStreamInfo *cltPtr;
  1735.     int priority;
  1736.     Mig_ArchStats *archPtr;    /* For statistics. */
  1737.     
  1738.  
  1739.     down = migdPtr->info.state == MIG_HOST_DOWN;
  1740.     if (global_Debug > 2) {
  1741.     PRINT_PID;
  1742.     fprintf(stderr, "RecordEvictions: %s %s.\n",
  1743.            migdPtr->name, down ? "down" : "evicting foreigners");
  1744.     }
  1745.  
  1746.     if (migd_DoStats) {
  1747.     archPtr = &global_Stats.archStats[migdPtr->archType];
  1748.     if (!down) {
  1749.         int noInput = (migdPtr->info.loadVec.noInput + 30) / 60 ;
  1750.         archPtr->nonIdleTransitions++;
  1751.         ADD_WITH_OVERFLOW(archPtr->counters.idleTimeWhenActive,
  1752.                   noInput);
  1753.         ADD_WITH_OVERFLOW(archPtr->squared.idleTimeWhenActive,
  1754.                   noInput * noInput);
  1755.     }
  1756.     }
  1757.  
  1758.  
  1759.     while (!List_IsEmpty(&migdPtr->clientList)) {
  1760.     listPtr = List_First(&migdPtr->clientList);
  1761.     List_Remove(listPtr);
  1762.     reqPtr = NEXT_HOST_REQUEST_TO_INFO(listPtr);
  1763.     if (global_Debug > 1 && !down) {
  1764.         PRINT_PID;
  1765.         fprintf(stderr, "RecordEvictions: %s evicting client %x.\n",
  1766.             migdPtr->name,
  1767.            (reqPtr->flags & MIG_PROC_AGENT) ? 
  1768.            reqPtr->client.processID : 
  1769.            reqPtr->client.cltPtr->processID);
  1770.     }
  1771.     RevokePermission(reqPtr, REVOKE_EVICT);
  1772.         
  1773.     if (migd_DoStats) {
  1774.         int curTime = time(0);
  1775.         int timeToEviction = curTime - reqPtr->timestamp;
  1776.         archPtr->counters.timeToEviction += timeToEviction;
  1777.         archPtr->squared.timeToEviction += timeToEviction * timeToEviction;
  1778.         ADD_WITH_OVERFLOW(archPtr->counters.hostIdleEvicted,
  1779.                   reqPtr->idleTime);
  1780.         ADD_WITH_OVERFLOW(archPtr->squared.hostIdleEvicted,
  1781.                   reqPtr->idleTime * reqPtr->idleTime);
  1782.         
  1783.     }
  1784.     free((char *) reqPtr);
  1785.     }
  1786.     migdPtr->flags &= ~(MIGD_CHECK_COUNT | MIGD_WAS_EMPTY);
  1787.     for (priority = MIG_LOW_PRIORITY; priority <= MIG_HIGH_PRIORITY;
  1788.      priority++) {
  1789.     migdPtr->info.foreign[priority] = 0;
  1790.     }
  1791.     /*
  1792.      * Clear out the last host assignment, since after a machine evicts or
  1793.      * crashes we don't care who last used it.
  1794.      */
  1795.     migdPtr->lastHostAssigned = -1;
  1796.  
  1797.     if (HostIsIdle(migdPtr)) {
  1798.     List_Remove((List_Links *) migdPtr);
  1799.     }
  1800. }
  1801.  
  1802.  
  1803. /*
  1804.  *----------------------------------------------------------------------
  1805.  *
  1806.  * TellClient --
  1807.  *
  1808.  *    Pass a number to a client.  It's either the ID of a host that
  1809.  *    it no longer has permission to use, or 0 to indicate a new host
  1810.  *    may be available.
  1811.  *
  1812.  * Results:
  1813.  *    None.
  1814.  *
  1815.  * Side effects:
  1816.  *    Allocates a message buffer and adds it to the clients list.  Makes
  1817.  *     the client pdev readable.
  1818.  *
  1819.  *----------------------------------------------------------------------
  1820.  */
  1821.  
  1822. static void
  1823. TellClient(cltPtr, msg)
  1824.     Migd_OpenStreamInfo *cltPtr; /* Info about client. */
  1825.     int msg;             /* ID of host, or 0. */
  1826. {
  1827.     MessageBlock *msgPtr;
  1828.  
  1829.     if (global_Debug > 4) {
  1830.     PRINT_PID;
  1831.     fprintf(stderr, "TellClient: telling client %x value %d.\n",
  1832.            cltPtr->processID, msg);
  1833.     }
  1834.     
  1835.     msgPtr = mnew(MessageBlock);
  1836.     List_InitElement(&msgPtr->links);
  1837.     msgPtr->msg = msg;
  1838.     if (List_IsEmpty(&cltPtr->messages)) {
  1839.     MigPdev_MakeReady(cltPtr->streamPtr, (ClientData) NULL);
  1840.     }
  1841.     List_Insert((List_Links *) msgPtr, LIST_ATREAR(&cltPtr->messages));
  1842. }
  1843.  
  1844.  
  1845. /*
  1846.  *----------------------------------------------------------------------
  1847.  *
  1848.  * RevokePermission  --
  1849.  *
  1850.  *    Notify a client that it has lost its permission to use a host.
  1851.  *
  1852.  * Results:
  1853.  *    None.
  1854.  *
  1855.  * Side effects:
  1856.  *    Sends a message.  Removes request from per-client list and per-machine
  1857.  *    list.
  1858.  *
  1859.  *----------------------------------------------------------------------
  1860.  */
  1861.  
  1862. static void
  1863. RevokePermission(reqPtr, action)
  1864.     RequestInfo *reqPtr;
  1865.     RevokeAction action;
  1866. {
  1867.     Migd_Info *migdPtr;
  1868.     Migd_OpenStreamInfo *cltPtr;
  1869.  
  1870.     migdPtr = reqPtr->migdPtr;
  1871.     migdPtr->info.foreign[reqPtr->priority] -= reqPtr->numProcessors;
  1872.     
  1873.     List_Remove(&reqPtr->nextInUse);
  1874. #ifdef DEBUG_LIST_REMOVE
  1875.     /*
  1876.      * Zap the element just to be sure.
  1877.      */
  1878.     List_InitElement(&reqPtr->nextInUse);
  1879. #endif /* DEBUG_LIST_REMOVE */
  1880.     
  1881.     if (!(reqPtr->flags & MIG_PROC_AGENT)) {
  1882.     List_Remove((List_Links *) reqPtr);
  1883.     cltPtr = reqPtr->client.cltPtr;
  1884.     TellClient(cltPtr, migdPtr->info.hostID);
  1885.     cltPtr->numInUse--;
  1886.     if (cltPtr->numInUse == 0) {
  1887.         cltPtr->stoleTime = 0;
  1888.     }
  1889.     if (action == REVOKE_EVICT) {
  1890.         cltPtr->numEvicted++;
  1891.     } else if (action == REVOKE_STOLEN) {
  1892.         cltPtr->numStolen++;
  1893.         cltPtr->stoleTime = time(0);
  1894.     }
  1895.     } else if (action == REVOKE_STOLEN) {
  1896.     /*
  1897.      * Request was on behalf of another process, so we don't
  1898.      * increment the client numStolen field and instead add it
  1899.      * in to the totals independently.  (For regular clients we
  1900.      * accumulate multiple reclaims/client and then the "squared"
  1901.      * statistic weights clustered reclaimed hosts.)
  1902.      */
  1903.     if (migd_DoStats) {
  1904.         global_Stats.archStats[migdPtr->archType].counters.reclaimed++;
  1905.         global_Stats.archStats[migdPtr->archType].squared.reclaimed++;
  1906.     }
  1907.     } else if (action == REVOKE_EVICT) {
  1908.     /*
  1909.      * Request was on behalf of another process, so we don't
  1910.      * increment the client numEvicted field and instead add it
  1911.      * in to the totals independently.  (For regular clients we
  1912.      * accumulate multiple evictions/client and then the "squared"
  1913.      * statistic weights clustered evictions.)
  1914.      */
  1915.     if (migd_DoStats) {
  1916.         global_Stats.archStats[migdPtr->archType].counters.evicted++;
  1917.         global_Stats.archStats[migdPtr->archType].squared.evicted++;
  1918.     }
  1919.     }
  1920. }
  1921.  
  1922.  
  1923. /*
  1924.  *----------------------------------------------------------------------
  1925.  *
  1926.  * Global_GetUpdate --
  1927.  *
  1928.  *    Return an update message to a client.  This is an ioctl
  1929.  *     invoked by the client when the client's stream becomes
  1930.  *    readable.
  1931.  *
  1932.  * Results:
  1933.  *    On error, a non-zero error status is returned, else 0.
  1934.  *
  1935.  * Side effects:
  1936.  *    The message is freed up.  If it's the last message in the
  1937.  *    client's queue, the client is changed to no longer be selectable.
  1938.  *
  1939.  *----------------------------------------------------------------------
  1940.  */
  1941.  
  1942. /* ARGSUSED */
  1943. int
  1944. Global_GetUpdate(cltPtr, command, inBuffer, inBufSize, outBuffer,
  1945.            outBufSizePtr)
  1946.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  1947.                    the request. */
  1948.     int command;        /* Ignored. */
  1949.     char *inBuffer;        /* Buffer to get arguments from, not used. */
  1950.     int inBufSize;        /* Size of the input buffer, not used. */
  1951.     char *outBuffer;        /* Buffer to place results. */
  1952.     int *outBufSizePtr;        /* Size of the output buffer. */
  1953. {
  1954.     int *intPtr;
  1955.     List_Links *listPtr;
  1956.     MessageBlock *msgPtr;
  1957.     
  1958.     if (global_Debug > 1) {
  1959.     PRINT_PID;
  1960.     fprintf(stderr, "Global_GetUpdate called by process %x\n",
  1961.            cltPtr->processID);
  1962.     }
  1963.     if (*outBufSizePtr < sizeof(int)) {
  1964.     if (global_Debug > 0) {
  1965.         SYSLOG2(LOG_WARNING,
  1966.            "Global_GetUpdate: bad output buffer size (%d) from process %x\n",
  1967.            *outBufSizePtr, cltPtr->processID);
  1968.     }
  1969.     return(EINVAL);
  1970.     }
  1971.     if (List_IsEmpty(&cltPtr->messages)) {
  1972.     if (global_Debug > 1) {
  1973.         PRINT_PID;
  1974.         fprintf(stderr,
  1975.            "Global_GetUpdate: no message for process %x\n",
  1976.            cltPtr->processID);
  1977.     }
  1978.     return(EAGAIN);
  1979.     }
  1980.     listPtr = List_First(&cltPtr->messages);
  1981.     List_Remove(listPtr);
  1982.     if (List_IsEmpty(&cltPtr->messages)) {
  1983.     cltPtr->defaultSelBits &= ~FS_READ;
  1984.     }
  1985.     msgPtr = (MessageBlock *) listPtr;
  1986.     intPtr = (int *) outBuffer;
  1987.     *intPtr = msgPtr->msg;
  1988.     *outBufSizePtr = sizeof(int);
  1989.     free((char *) listPtr);
  1990.     if (global_Debug > 1) {
  1991.     PRINT_PID;
  1992.     fprintf(stderr,
  1993.            "Global_GetUpdate: message for process %x is %d\n",
  1994.            cltPtr->processID, msgPtr->msg);
  1995.     }
  1996.     return(0);
  1997. }
  1998.  
  1999.  
  2000.  
  2001. /*
  2002.  *----------------------------------------------------------------------
  2003.  *
  2004.  * Global_RemoveHost --
  2005.  *
  2006.  *    Remove a host completely from the database.  This may be done
  2007.  *    when a host is removed from the system, for example.
  2008.  *
  2009.  * Results:
  2010.  *    On error, a non-zero error status is returned, else 0.
  2011.  *
  2012.  * Side effects:
  2013.  *    The host(s) are removed from our lists and a new checkpoint is
  2014.  *    written.
  2015.  *
  2016.  *----------------------------------------------------------------------
  2017.  */
  2018.  
  2019. /* ARGSUSED */
  2020. int
  2021. Global_RemoveHost(cltPtr, command, inBuffer, inBufSize, outBuffer,
  2022.            outBufSizePtr)
  2023.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  2024.                    the request. */
  2025.     int command;        /* Ignored. */
  2026.     char *inBuffer;        /* Buffer to get arguments from. */
  2027.     int inBufSize;        /* Size of the input buffer. */
  2028.     char *outBuffer;        /* Buffer to place results, not used. */
  2029.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  2030. {
  2031.     int *hostPtr;        /* Pointer into input buffer. */
  2032.     int i;            /* Counter. */
  2033.     int numArgs;        /* Number of args (host IDs). */
  2034.     int status;            /* Status from subroutine calls. */
  2035.  
  2036.     if ((inBufSize % sizeof(int)) != 0 || inBufSize <= 0) {
  2037.     if (global_Debug > 0) {
  2038.         SYSLOG2(LOG_WARNING,
  2039.            "Global_RemoveHost: bad input buffer size (%d) from process %x\n",
  2040.            inBufSize, cltPtr->processID);
  2041.     }
  2042.     return(EINVAL);
  2043.     }
  2044.     numArgs = inBufSize / sizeof(int);
  2045.     hostPtr = (int *) inBuffer;
  2046.     for (i = 0; i < numArgs; i++) {
  2047.     status = RemoveHost(*hostPtr);
  2048.     if (status != 0) {
  2049.         return(status);
  2050.     }
  2051.     }
  2052.     SaveCheckPoint((ClientData) NULL, time_ZeroSeconds);
  2053.     return(0);
  2054. }
  2055.  
  2056.  
  2057.  
  2058. /*
  2059.  *----------------------------------------------------------------------
  2060.  *
  2061.  * RemoveHost --
  2062.  *
  2063.  *    Remove a single host from our knowledge.
  2064.  *
  2065.  * Results:
  2066.  *    On error, a non-zero error status is returned, else 0.
  2067.  *
  2068.  * Side effects:
  2069.  *    None.
  2070.  *
  2071.  *----------------------------------------------------------------------
  2072.  */
  2073.  
  2074. static int
  2075. RemoveHost(hostID)
  2076.     int hostID;            /* Host to remove. */
  2077. {
  2078.     Migd_Info *migdPtr;
  2079.  
  2080.     if (global_Debug > 1) {
  2081.     PRINT_PID;
  2082.     fprintf(stderr, "RemoveHost(%d) -\n", hostID);
  2083.     }
  2084.  
  2085.     if (hostID > maxHosts || hostID <= 0) {
  2086.     if (global_Debug > 0) {
  2087.         PRINT_PID;
  2088.         fprintf(stderr, "RemoveHost: bad value of hostID: %d\n", hostID);
  2089.     }
  2090.     return(EINVAL);
  2091.     }
  2092.     migdPtr = migInfoArray[hostID];
  2093.     if (migdPtr != (Migd_Info *) NULL) {
  2094.     if (migdPtr->info.state != MIG_HOST_DOWN) {
  2095.         if (global_Debug > 0) {
  2096.         PRINT_PID;
  2097.         fprintf(stderr, "RemoveHost: %s is up; not removing.\n",
  2098.             migdPtr->name);
  2099.         }
  2100.         return(EINVAL);
  2101.     }
  2102.     if (migdPtr->name != (char *) NULL) {
  2103.         free(migdPtr->name);
  2104.     }
  2105.     free((char *) migdPtr);
  2106.     migInfoArray[hostID] = (Migd_Info *) NULL;
  2107.     } else if (global_Debug > 0) {
  2108.     PRINT_PID;
  2109.     fprintf(stderr, "RemoveHost(%d) - didn't know about host.\n", hostID);
  2110.     }
  2111.     return(0);
  2112. }
  2113.  
  2114. /*
  2115.  *----------------------------------------------------------------------
  2116.  *
  2117.  * Global_IsHostUp --
  2118.  *
  2119.  *    Return whether the specified host is up.
  2120.  *
  2121.  * Results:
  2122.  *    TRUE if the host exists and is up, FALSE otherwise.
  2123.  *
  2124.  * Side effects:
  2125.  *    None.
  2126.  *
  2127.  *----------------------------------------------------------------------
  2128.  */
  2129.  
  2130. int
  2131. Global_IsHostUp(hostID)
  2132.     int hostID;            /* Host to check on. */
  2133. {
  2134.     Migd_Info *migdPtr;
  2135.  
  2136.     if (global_Debug > 2) {
  2137.     PRINT_PID;
  2138.     fprintf(stderr, "Global_IsHostUp(%d) -\n", hostID);
  2139.     }
  2140.  
  2141.     if (hostID > maxHosts || hostID <= 0) {
  2142.     SYSLOG1(LOG_ERR, "Global_IsHostUp: bad value of hostID: %d\n", hostID);
  2143.     return(0);
  2144.     }
  2145.     migdPtr = migInfoArray[hostID];
  2146.     if ((migdPtr != (Migd_Info *) NULL) &&
  2147.     (migdPtr->info.state != MIG_HOST_DOWN)) {
  2148.     return(1);
  2149.     }
  2150.     return(0);
  2151. }
  2152.  
  2153. /*
  2154.  *----------------------------------------------------------------------
  2155.  *
  2156.  * Global_ChangeState --
  2157.  *
  2158.  *    A host has changed from accepting processes to not accepting them,
  2159.  *    or vice-versa.  If not accepting, then notify processes about
  2160.  *    any evictions that might have occurred.
  2161.  *
  2162.  * Results:
  2163.  *    On error, a non-zero error status is returned, else 0.
  2164.  *
  2165.  * Side effects:
  2166.  *    Message(s) sent to clients.  Host may be added to or removed from
  2167.  *    list of idle hosts.
  2168.  *
  2169.  *----------------------------------------------------------------------
  2170.  */
  2171.  
  2172. /* ARGSUSED */
  2173. int
  2174. Global_ChangeState(cltPtr, command, inBuffer, inBufSize, outBuffer,
  2175.            outBufSizePtr)
  2176.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  2177.                    the request. */
  2178.     int command;        /* Ignored. */
  2179.     char *inBuffer;        /* Buffer to get arguments from. */
  2180.     int inBufSize;        /* Size of the input buffer. */
  2181.     char *outBuffer;        /* Buffer to place results, not used. */
  2182.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  2183. {
  2184.     int *statePtr;
  2185.     int host;
  2186.     Migd_Info *migdPtr;
  2187.  
  2188.     if (cltPtr->type != MIGD_DAEMON) {
  2189.     if (global_Debug > 0) {
  2190.         PRINT_PID;
  2191.         fprintf(stderr,
  2192.            "Global_ChangeState: non-daemon trying to invoke CHANGE ioctl; pid %x state %x\n",
  2193.            cltPtr->processID, (int) cltPtr->type);
  2194.     }
  2195.     return(EPERM);
  2196.     }
  2197.  
  2198.     if (inBufSize != sizeof(int)) {
  2199.     if (global_Debug > 0) {
  2200.         SYSLOG2(LOG_WARNING,
  2201.            "Global_ChangeState: wrong size input (%d bytes) from process %x\n",
  2202.            inBufSize, cltPtr->processID);
  2203.     }
  2204.     return(EINVAL);
  2205.     }
  2206.  
  2207.     host = cltPtr->host;
  2208.     statePtr = (int *) inBuffer;
  2209.  
  2210.     migdPtr = CltToMigd(cltPtr);
  2211.     if (migdPtr == (Migd_Info *) NULL) {
  2212.     SYSLOG0(LOG_ERR, "Global_ChangeState: never heard from this host?  Exiting.\n");
  2213.     exit(1);
  2214.     }
  2215.  
  2216.     if (global_Debug > 2) {
  2217.     PRINT_PID;
  2218.     fprintf(stderr, "Global_ChangeState called for %s => state %d.\n",
  2219.            migdPtr->name,
  2220.            *statePtr);
  2221.     }
  2222.     
  2223.     switch (*statePtr) {
  2224.     case MIG_HOST_ACTIVE:
  2225.     case MIG_HOST_REFUSES: {
  2226.         /*
  2227.          * Host is evicting any foreign processes.
  2228.          */
  2229.         if (global_Debug > 3) {
  2230.         PRINT_PID;
  2231.         fprintf(stderr, "Host is active or is refusing migration.\n");
  2232.         }
  2233.         RecordEvictions(migdPtr);
  2234.         break;
  2235.     }
  2236.     case MIG_HOST_IDLE: {
  2237.         /*
  2238.          * Actually, this case should never be reached.
  2239.          */
  2240.         if (global_Debug > 0) {
  2241.         PRINT_PID;
  2242.         fprintf(stderr, "Changed state to idle??\n");
  2243.         }
  2244.         InsertIdle(migdPtr);
  2245.         break;
  2246.     }
  2247.     default: {
  2248.         PRINT_PID;
  2249.         fprintf(stderr, "Invalid state!\n");
  2250.         return(EINVAL);
  2251.     }
  2252.     }
  2253.     hostCounts[migdPtr->archType][migdPtr->info.state]--;
  2254.     migdPtr->info.state = *statePtr;
  2255.     hostCounts[migdPtr->archType][migdPtr->info.state]++;
  2256.  
  2257.     return(0);
  2258. }
  2259.  
  2260.  
  2261. /*
  2262.  *----------------------------------------------------------------------
  2263.  *
  2264.  * Global_HostUp --
  2265.  *
  2266.  *    Mark a host as being up, the first time its daemon talks to us.
  2267.  *
  2268.  * Results:
  2269.  *    0 for success, or an errno indicating the error.
  2270.  *    EPERM indicates that a non-root process tried to tell us it
  2271.  *     was the daemon.
  2272.  *
  2273.  * Side effects:
  2274.  *    The host is added to the list of active hosts.  
  2275.  *
  2276.  *----------------------------------------------------------------------
  2277.  */
  2278.  
  2279. /* ARGSUSED */
  2280. int
  2281. Global_HostUp(cltPtr, command, inBuffer, inBufSize, outBuffer,
  2282.            outBufSizePtr)
  2283.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  2284.                    the request. */
  2285.     int command;        /* Ignored. */
  2286.     char *inBuffer;        /* Buffer to get arguments from. */
  2287.     int inBufSize;        /* Size of the input buffer. */
  2288.     char *outBuffer;        /* Buffer to place results, not used. */
  2289.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  2290. {
  2291.     Mig_Info *infoPtr;
  2292.     Migd_Info *migdPtr;
  2293.     Host_Entry *hostPtr;
  2294.     Migd_OpenStreamInfo *oldCltPtr;  /* Information about any previous client
  2295.                         from this host. */
  2296.     int status;
  2297.     struct timeval time;
  2298.     
  2299.     if (global_Debug > 3) {
  2300.     PRINT_PID;
  2301.     fprintf(stderr, "Global_HostUp called.\n");
  2302.     }
  2303.  
  2304.     status = gettimeofday(&time, (struct timezone *) NULL);
  2305.     if (status == -1) {
  2306.     SYSLOG1(LOG_ERR, "Error in gettimeofday: %s", strerror(errno));
  2307.     exit(1);
  2308.     }
  2309.  
  2310.     if (inBufSize != sizeof(Mig_Info)) {
  2311.     if (global_Debug > 0) {
  2312.         SYSLOG2(LOG_WARNING,
  2313.            "Global_HostUp: bad input buffer size (%d) from process %x\n",
  2314.            inBufSize, cltPtr->processID);
  2315.     }
  2316.     return(EINVAL);
  2317.     }
  2318.  
  2319.     /*
  2320.      * Flag a connection as belonging to a daemon, permitting
  2321.      * it to perform privileged operations.   Set the format
  2322.      * value in the info struct, so that writes can be swapped if
  2323.      * needed.
  2324.      */
  2325. #ifndef DEBUG
  2326.     if (global_Debug == 0 && cltPtr->user != PROC_SUPER_USER_ID) {
  2327.     return(EPERM);
  2328.     }
  2329. #endif /* DEBUG */
  2330.  
  2331.  
  2332.     infoPtr = (Mig_Info *) inBuffer;
  2333.  
  2334.     if (cltPtr->host > maxHosts) {
  2335.     /*
  2336.      * XXX We should handle this obscure case by growing the array of
  2337.      * hosts, but skip it for the time being.
  2338.      */
  2339.     SYSLOG1(LOG_ERR,
  2340.            "Never heard of host %d, and ID is too big.\n", cltPtr->host);
  2341.     return(EINVAL);
  2342.     }
  2343.     if (migInfoArray[cltPtr->host] == (Migd_Info *) NULL) {
  2344.     /*
  2345.      * This can happen if a new host is added to the system
  2346.      * after the global daemon starts up, or a host record has been
  2347.      * removed. 
  2348.      */
  2349.     hostPtr = Host_ByID(cltPtr->host);
  2350.     if (hostPtr == (Host_Entry *) NULL) {
  2351.         SYSLOG1(LOG_ERR, "No entry in host database for host %d.\n",
  2352.            cltPtr->host);
  2353.         return(EINVAL);
  2354.     }
  2355.     CreateMigdRecord(hostPtr);
  2356.     Host_End();
  2357.     }
  2358.     migdPtr = migInfoArray[cltPtr->host];
  2359.  
  2360.     if (global_Debug > 1) {
  2361.     PRINT_PID;
  2362.     fprintf(stderr,
  2363.         "Global_HostUp - %s pid %x boot %d version %d maxProcs %d\n",
  2364.         migdPtr->name, cltPtr->processID,
  2365.         infoPtr->bootTime, infoPtr->migVersion,
  2366.            infoPtr->maxProcs);
  2367.     }
  2368.  
  2369.     if (migdPtr->cltPtr != (Migd_OpenStreamInfo *) NULL) {
  2370.     oldCltPtr = migdPtr->cltPtr;
  2371.     /*
  2372.      * Check once again whether the host is really down.  If a host reboots
  2373.      * quickly, we might otherwise think it's still up and try to signal
  2374.      * a process.  If we're really unlikely, the host rebooted and the
  2375.      * process of the new daemon is the same as the daemon the last time
  2376.      * the host was up, and we'll kill the new daemon (or some other
  2377.      * random process).  We could solve this problem if each boot
  2378.      * incremented some version number that got passed to the global
  2379.      * daemon, but we don't have such a capability (yet).
  2380.      *
  2381.      * Another potential problem: the host migd gets a stale handle
  2382.      * and closes and reopens the global pdev, and we have to recognize
  2383.      * that and refrain from terminating it as if it were a leftover
  2384.      * migd process.
  2385.      */
  2386.     if (oldCltPtr->processID == cltPtr->processID) {
  2387.         if (global_Debug > 1) {
  2388.         PRINT_PID;
  2389.         fprintf(stderr,
  2390.             "Global_HostUp - %s reopening unclosed connection.\n",
  2391.             migdPtr->name);
  2392.         }
  2393.         (void) Global_HostDown(cltPtr->host, 0);
  2394.     } else if (migdPtr->info.loadVec.timestamp <
  2395.         time.tv_sec - MIG_TIMEOUT) {
  2396.         if (global_Debug > 1) {
  2397.         PRINT_PID;
  2398.         fprintf(stderr,
  2399.             "Global_HostUp - marking %s down (curTime %d, updated %d).\n",
  2400.             migdPtr->name, time.tv_sec,
  2401.             migdPtr->info.loadVec.timestamp);
  2402.         }
  2403.         (void) Global_HostDown(cltPtr->host, 0);
  2404.     }
  2405.     if (migdPtr->info.state != MIG_HOST_DOWN) {
  2406.         if (global_Debug > 1) {
  2407.         PRINT_PID;
  2408.         fprintf(stderr,
  2409.             "Already talking to a daemon on %s.  Signalling pid %x.\n",
  2410.             migdPtr->name, oldCltPtr->processID);
  2411.         }
  2412.         status = Sig_Send(SIG_TERM, oldCltPtr->processID, 0);
  2413.         if (status != SUCCESS) {
  2414.         if (global_Debug > 0) {
  2415.             PRINT_PID;
  2416.             fprintf(stderr, "SendSignal: error sending signal to process %x: %s\n",
  2417.                 oldCltPtr->processID, Stat_GetMsg(status));
  2418.         }
  2419.         Global_HostDown(cltPtr->host, 0);
  2420.         } else {
  2421.         return(EBUSY);
  2422.         }
  2423.     } else {
  2424.         if (global_Debug > 1) {
  2425.         PRINT_PID;
  2426.         fprintf(stderr,
  2427.                "Received new open from host %s; closing prior stream.\n",
  2428.                migdPtr->name);
  2429.         }
  2430.     }
  2431.     } 
  2432.  
  2433.     /*
  2434.      * Check for migds that are a bit confused about their state.
  2435.      */
  2436.     if (infoPtr->state == MIG_HOST_IDLE && !infoPtr->loadVec.allowMigration) {
  2437.     if (global_Debug > 0) {
  2438.         PRINT_PID;
  2439.         fprintf(stderr,
  2440.             "Host %s marked as idle but not allowing migration.\n",
  2441.             migdPtr->name);
  2442.     }
  2443.     infoPtr->state = MIG_HOST_REFUSES;
  2444.     }
  2445. #ifdef USE_GLOBAL_CLOCK
  2446.     /*
  2447.      * Update the time of day to use the global daemon's idea of the time,
  2448.      * to keep things in sync and avoid calling a client down just because
  2449.      * of clock skew.  Check the bootstamp for clock skew too.
  2450.      */
  2451.     infoPtr->loadVec.timestamp = time.tv_sec;
  2452.     if (infoPtr->bootTime > time.tv_sec) {
  2453.     infoPtr->bootTime = time.tv_sec;
  2454.     }
  2455. #endif /* USE_GLOBAL_CLOCK */
  2456.     migdPtr->info = *infoPtr;
  2457.     migdPtr->cltPtr = cltPtr;
  2458.     cltPtr->type = MIGD_DAEMON;
  2459.     cltPtr->defaultSelBits = FS_WRITE;
  2460.  
  2461.     /*
  2462.      * Add the host to appropriate queue, and modify our counters.
  2463.      */
  2464.     hostCounts[migdPtr->archType][MIG_HOST_DOWN]--;
  2465.     hostCounts[migdPtr->archType][infoPtr->state]++;
  2466.     if (infoPtr->state == MIG_HOST_IDLE) {
  2467.     InsertIdle(migdPtr);
  2468.     }
  2469.  
  2470.     hostsUp++;
  2471.     
  2472.     return(0);
  2473. }
  2474.  
  2475.  
  2476.  
  2477. /*
  2478.  *----------------------------------------------------------------------
  2479.  *
  2480.  * EndCallBack --
  2481.  *
  2482.  *    Just a callback used by Fs_Dispatch when we want to quit
  2483.  *    but can't at the moment.  It takes (and ignores) the
  2484.  *    Fs_Dispatch callback arguments.
  2485.  *
  2486.  * Results:
  2487.  *    None.
  2488.  *
  2489.  * Side effects:
  2490.  *    Global_End is called, and the process exits.
  2491.  *
  2492.  *----------------------------------------------------------------------
  2493.  */
  2494.  
  2495. /* ARGSUSED */
  2496. static void
  2497. EndCallBack(clientData, time)
  2498.     ClientData clientData;    /* Generic callback arg, not used.  */
  2499.     Time time;            /* Generic callback arg, not used.  */
  2500. {
  2501.     if (global_Debug > 1) {
  2502.     PRINT_PID;
  2503.     fprintf(stderr, "EndCallBack -\n");
  2504.     }
  2505.     
  2506.     Global_End();
  2507. }
  2508.  
  2509. /*
  2510.  *----------------------------------------------------------------------
  2511.  *
  2512.  * Global_HostDown --
  2513.  *
  2514.  *    Mark a host as being down.  This may happen when a pdev for the
  2515.  *    daemon on that host is closed, or if it doesn't update its information
  2516.  *    in a timely fashion.  If it's really closed, we clean up state
  2517.  *    associated with it.
  2518.  *
  2519.  * Results:
  2520.  *    0 for success, or -1 and an errno for failure.
  2521.  *
  2522.  * Side effects:
  2523.  *    The host is removed from any lists of active hosts.  Any clients
  2524.  *    accessing the host are notified that it is down.
  2525.  *
  2526.  *----------------------------------------------------------------------
  2527.  */
  2528.  
  2529. int
  2530. Global_HostDown(hostID, closed)
  2531.     int hostID;
  2532.     int closed;            /* whether its stream was closed */
  2533. {
  2534.     Migd_Info *migdPtr;
  2535.  
  2536.     if (hostID > maxHosts || migInfoArray[hostID] == (Migd_Info *) NULL) {
  2537.     PRINT_PID;
  2538.     fprintf(stderr, "Global_HostDown: bad value of hostID: %d\n",
  2539.            hostID);
  2540.     errno = EINVAL;
  2541.     return(-1);
  2542.     }
  2543.     migdPtr = migInfoArray[hostID];
  2544.     if (global_Debug > 1) {
  2545.     PRINT_PID;
  2546.     fprintf(stderr, "Global_HostDown(host=%s(%d), closed=%d) called.\n",
  2547.            migdPtr->name, hostID, closed);
  2548.     }
  2549.  
  2550.     if (closed) {
  2551.     /*
  2552.      * We're no longer talking to the daemon with a pdev connection.
  2553.      */
  2554.     migdPtr->cltPtr = (Migd_OpenStreamInfo *) NULL;
  2555.     } else {
  2556.     /*
  2557.      * This connection is unusable... later closes should be ignored.
  2558.      */
  2559.     migdPtr->cltPtr->type = MIGD_CLOSED;
  2560.     }
  2561.     if (HostIsIdle(migdPtr)) {
  2562.     List_Remove((List_Links *) migdPtr);
  2563.     }
  2564.     hostCounts[migdPtr->archType][migdPtr->info.state]--;
  2565.     migdPtr->info.state = MIG_HOST_DOWN;
  2566.     hostCounts[migdPtr->archType][MIG_HOST_DOWN]++;
  2567.     RecordEvictions(migdPtr);
  2568.  
  2569.     hostsUp--;
  2570.     if (hostsUp <= 0 && migd_Quit) {
  2571.     if (closed) {
  2572.         /*
  2573.          * Set up a callback to exit, rather than doing it right now,
  2574.          * since we want to return from any Pdev_Close callback before
  2575.          * trying to close the master.
  2576.          */
  2577.         Fs_TimeoutHandlerDestroy(migd_TimeoutToken);
  2578.         (void) Fs_TimeoutHandlerCreate(time_ZeroSeconds, TRUE,
  2579.                        EndCallBack, (ClientData) NULL);
  2580.     } else {
  2581.         Global_End();
  2582.     }
  2583.     }
  2584.     return(0);
  2585. }
  2586.  
  2587.  
  2588. /*
  2589.  *----------------------------------------------------------------------
  2590.  *
  2591.  * Global_UpdateLoad --
  2592.  *
  2593.  *    Update the load vector corresponding to a host.
  2594.  *
  2595.  * Results:
  2596.  *    0 for success, or -1 for failure, with errno indicating the error.
  2597.  *
  2598.  * Side effects:
  2599.  *    The host may be moved from one queue to another if its status
  2600.  *    changes.
  2601.  *
  2602.  *----------------------------------------------------------------------
  2603.  */
  2604.  
  2605. int
  2606. Global_UpdateLoad(cltPtr, vecPtr)
  2607.     Migd_OpenStreamInfo *cltPtr;
  2608.     Mig_LoadVector *vecPtr;
  2609. {
  2610.     int host;
  2611.     Migd_Info *migdPtr;
  2612.     Mig_LoadVector *oldVecPtr;
  2613.     int oldAllow;
  2614.     int oldForeign;
  2615.     int status;
  2616.     struct timeval time;
  2617.  
  2618.     host = cltPtr->host;
  2619.     
  2620.     migdPtr = CltToMigd(cltPtr);
  2621.     if (migdPtr == (Migd_Info *) NULL) {
  2622.     SYSLOG0(LOG_ERR, "Global_UpdateLoad: never heard from this host?  Exiting.\n");
  2623.     exit(1);
  2624.     }
  2625.     if (global_Debug > 3) {
  2626.     PRINT_PID;
  2627.     fprintf(stderr, "Global_UpdateLoad called for %s. time %d noInput %d foreign %d allowMigration %d utils %d %d %d lengths %.2f %.2f %.2f\n",
  2628.            migdPtr->name,
  2629.            vecPtr->timestamp,
  2630.            vecPtr->noInput,
  2631.            vecPtr->foreignProcs,
  2632.            vecPtr->allowMigration,
  2633.            vecPtr->utils[0], vecPtr->utils[1], vecPtr->utils[2],
  2634.            vecPtr->lengths[0], vecPtr->lengths[1], vecPtr->lengths[2]);
  2635.     }
  2636.     if (migdPtr->info.state == MIG_HOST_DOWN) {
  2637.     if (global_Debug) {
  2638.         PRINT_PID;
  2639.         fprintf(stderr, "Global_UpdateLoad: Thought %s was down.\n",
  2640.            migdPtr->name);
  2641.     }
  2642.     hostCounts[migdPtr->archType][MIG_HOST_DOWN]--;
  2643.     migdPtr->info.state = vecPtr->allowMigration ? MIG_HOST_ACTIVE :
  2644.         MIG_HOST_REFUSES;
  2645.     hostCounts[migdPtr->archType][migdPtr->info.state]++;
  2646.     hostsUp++;
  2647.     }
  2648.     oldVecPtr = &migdPtr->info.loadVec; 
  2649.     if (global_Debug > 3) {
  2650.     PRINT_PID;
  2651.     fprintf(stderr, "Global_UpdateLoad: Old values: time %d noInput %d foreign %d allowMigration %d utils %d %d %d lengths %.2f %.2f %.2f\n",
  2652.            oldVecPtr->timestamp,
  2653.            oldVecPtr->noInput,
  2654.            oldVecPtr->foreignProcs,
  2655.            oldVecPtr->allowMigration,
  2656.            oldVecPtr->utils[0],
  2657.            oldVecPtr->utils[1],
  2658.            oldVecPtr->utils[2],
  2659.            oldVecPtr->lengths[0],
  2660.            oldVecPtr->lengths[1],
  2661.            oldVecPtr->lengths[2]);
  2662.     }
  2663.     oldAllow = oldVecPtr->allowMigration;
  2664.     oldForeign = oldVecPtr->foreignProcs;
  2665.     *oldVecPtr = *vecPtr;
  2666.  
  2667. #ifdef USE_GLOBAL_CLOCK
  2668.     /*
  2669.      * Update the time of day to use the global daemon's idea of the time,
  2670.      * to keep things in sync and avoid calling a client down just because
  2671.      * of clock skew.
  2672.      */
  2673.     status = gettimeofday(&time, (struct timezone *) NULL);
  2674.     if (status == -1) {
  2675.     SYSLOG1(LOG_ERR, "Error in gettimeofday: %s", strerror(errno));
  2676.     exit(1);
  2677.     }
  2678.     oldVecPtr->timestamp = time.tv_sec;
  2679. #endif /* USE_GLOBAL_CLOCK */
  2680.     if (oldAllow && !vecPtr->allowMigration) {
  2681.     /*
  2682.      * Host is evicting any foreign processes.
  2683.      */
  2684.     if (global_Debug > 2) {
  2685.         PRINT_PID;
  2686.         fprintf(stderr, "\t>>%s is no longer available<<\n", migdPtr->name);
  2687.     }
  2688.     if (HostIsIdle(migdPtr)) {
  2689.         List_Remove((List_Links *) migdPtr);
  2690.     }
  2691.     hostCounts[migdPtr->archType][migdPtr->info.state]--;
  2692.     migdPtr->info.state = MIG_HOST_ACTIVE;
  2693.     hostCounts[migdPtr->archType][MIG_HOST_ACTIVE]++;
  2694.     } else if (!oldAllow && vecPtr->allowMigration) {
  2695.     if (global_Debug > 2) {
  2696.         PRINT_PID;
  2697.         fprintf(stderr, "\t<<%s is now idle>>\n", migdPtr->name);
  2698.     }
  2699.     if (HostIsIdle(migdPtr)) {
  2700.         if (global_Debug > 0) {
  2701.         PRINT_PID;
  2702.         fprintf(stderr,
  2703.             "\t ** %s wasn't allowing migration but was idle\n",
  2704.             migdPtr->name);
  2705.         }
  2706.     } else {
  2707.         InsertIdle(migdPtr);
  2708.     }
  2709.     } else if (vecPtr->allowMigration && (migdPtr->flags & MIGD_CHECK_COUNT) &&
  2710.            (migdPtr->info.state == MIG_HOST_FULL ||
  2711.         migdPtr->info.state == MIG_HOST_PART_USED)) {
  2712.     if (oldForeign > 0 && vecPtr->foreignProcs == 0) {
  2713.         if (global_Debug > 1) {
  2714.         PRINT_PID;
  2715.         fprintf(stderr, "\t--%s now has no foreigners--\n",
  2716.             migdPtr->name);
  2717.         }
  2718.         ForceHostIdle(migdPtr);
  2719.     } else if (vecPtr->foreignProcs > 0) {
  2720.         /*
  2721.          * If during a checkpoint we noticed that the host was empty, and
  2722.          * now it isn't, we disable the MIGD_WAS_EMPTY flag.  This
  2723.          * way a host will be marked as having no foreign processes
  2724.          * and put back in the pool only if two checkpoints go by without
  2725.          * the host ever having foreign processes at the points when the
  2726.          * per-host migd sends us its data.
  2727.          */
  2728.         migdPtr->flags &= ~MIGD_WAS_EMPTY;
  2729.     }
  2730.     } else if (vecPtr->allowMigration &&
  2731.            (migdPtr->info.state == MIG_HOST_ACTIVE) &&
  2732.            vecPtr->foreignProcs == 0) {
  2733.     /*
  2734.      * Host must have evicted without later making the transition
  2735.      * from not allowing to allowing.  This can happen if eviction
  2736.      * takes a long time or if eviction is done via an ioctl from
  2737.      * a user rather than by detecting input.
  2738.      */
  2739.     if (global_Debug > 1) {
  2740.         PRINT_PID;
  2741.         fprintf(stderr, "\t--%s available again--\n",
  2742.            migdPtr->name);
  2743.     }
  2744.     ForceHostIdle(migdPtr);
  2745.     }
  2746.     return(0);
  2747. }
  2748.  
  2749.  
  2750. /*
  2751.  *----------------------------------------------------------------------
  2752.  *
  2753.  * RestoreCheckPoint --
  2754.  *
  2755.  *    Restore the last known state of the world from a checkpoint
  2756.  *    file.
  2757.  *
  2758.  * Results:
  2759.  *    None.
  2760.  *
  2761.  * Side effects:
  2762.  *    The state of each host in the checkpoint, and the statistics structure,
  2763.  *    are initialized.
  2764.  *
  2765.  *----------------------------------------------------------------------
  2766.  */
  2767.  
  2768. static void
  2769. RestoreCheckPoint()
  2770. {
  2771.  
  2772.     FILE *checkPoint;
  2773.     int hostID;
  2774.     int timestamp;
  2775.     Migd_Info *migdPtr;
  2776.     int numScanned;
  2777.     int hostsRead = 0;
  2778.     char buffer[BUFSIZ];
  2779.     
  2780.     if (global_Debug > 2) {
  2781.     PRINT_PID;
  2782.     fprintf(stderr, "RestoreCheckPoint -\n");
  2783.     }
  2784.     checkPoint = fopen(MIGD_CHECKPOINT_FILE, "r");
  2785.     if (checkPoint == (FILE *) NULL) {
  2786.     PRINT_PID;
  2787.     fprintf(stderr, "RestoreCheckPoint - error reading checkpoint: %s.\n",
  2788.            strerror(errno));
  2789.     return;
  2790.     }
  2791.     if (ReadStats(checkPoint) < 0) {
  2792.     PRINT_PID;
  2793.     SYSLOG1(stderr,
  2794.         "warning: RestoreCheckPoint - error reading statistics from checkpoint: %s.\n",
  2795.            strerror(errno));
  2796.     /*
  2797.      * Reinitialize statistics buffer.
  2798.      */
  2799.     InitStats();
  2800.     }
  2801.     while (1) {
  2802.     if (fgets(buffer, sizeof(buffer), checkPoint) == (char *) NULL) {
  2803.         break;
  2804.     }
  2805.     if (buffer[0] == '%') {
  2806.         if (global_Debug > 1) {
  2807.         PRINT_PID;
  2808.         fprintf(stderr, "RestoreCheckPoint: %s",
  2809.                buffer);
  2810.         }
  2811.         continue;
  2812.     }
  2813.     numScanned = sscanf(buffer, "%d %d", &hostID, ×tamp);
  2814.     if (numScanned < 0) {
  2815.         break;
  2816.     }
  2817.     if (numScanned != 2) {
  2818.         PRINT_PID;
  2819.         fprintf(stderr,
  2820.            "RestoreCheckPoint - scanned %d items from checkpoint file.\n",
  2821.            numScanned);
  2822.         break;
  2823.     }
  2824.     if (hostID <= 0 || hostID > maxKnownHost) {
  2825.         PRINT_PID;
  2826.         fprintf(stderr,
  2827.            "RestoreCheckPoint - invalid hostID %d.\n", hostID);
  2828.         break;
  2829.     }
  2830.     migdPtr = migInfoArray[hostID];
  2831.     if (migdPtr == (Migd_Info *) NULL ||
  2832.         migdPtr->info.loadVec.timestamp != 0) {
  2833.         PRINT_PID;
  2834.         fprintf(stderr,
  2835.            "RestoreCheckPoint - host %d NULL or non-zero.\n", hostID);
  2836.         break;
  2837.     }
  2838.     if (global_Debug > 2) {
  2839.         fprintf(stderr,
  2840.            "<%d,%d> ",
  2841.            hostID, timestamp);
  2842.     }
  2843.     migdPtr->info.loadVec.timestamp = timestamp;
  2844.     if (migdPtr->info.state != MIG_HOST_DOWN) {
  2845.         panic("RestoreCheckPoint: host was not in DOWN state before.\n");
  2846.     }
  2847.     hostsRead++;
  2848.     }
  2849.     if (global_Debug > 1) {
  2850.     fprintf(stderr, "\n%x: RestoreCheckPoint - read %d hosts.\n",
  2851.         migd_Pid, hostsRead);
  2852.     }
  2853.     (void) fclose(checkPoint);
  2854. }
  2855.  
  2856.  
  2857. /*
  2858.  *----------------------------------------------------------------------
  2859.  *
  2860.  * SaveCheckPoint --
  2861.  *
  2862.  *    Save the last known state of the world to a checkpoint
  2863.  *    file.  While we're at it, check for hosts we haven't heard from
  2864.  *    in a while, and check to make sure we're still controlling the
  2865.  *     real master pdev (someone else could have mistakenly removed it
  2866.  *     and started a second master, and new contacts would reach it instead
  2867.  *     of this process).
  2868.  *
  2869.  * Results:
  2870.  *    None.
  2871.  *
  2872.  * Side effects:
  2873.  *    Hosts may be marked as DOWN.
  2874.  *
  2875.  *----------------------------------------------------------------------
  2876.  */
  2877.  
  2878. /* ARGSUSED */
  2879. static void
  2880. SaveCheckPoint(clientData, timeArg)
  2881.     ClientData clientData;    /* Generic callback arg, not used.  */
  2882.     Time timeArg;        /* Generic callback arg, not used.  */
  2883. {
  2884.     FILE *checkPoint;
  2885.     Migd_Info *migdPtr;
  2886.     int i;
  2887.     struct timeval tv;
  2888.     int status;
  2889.     struct stat nameAtts;
  2890.     
  2891.     if (global_Debug > 1) {
  2892.     int t = time(0);
  2893.     PRINT_PID;
  2894.     fprintf(stderr, "Global daemon checkpoint: running on %s at %s",
  2895.         migd_HostName, ctime(&t));
  2896.     }
  2897.  
  2898. #ifdef 0
  2899.     if (lstat(migd_GlobalPdevName, &nameAtts) < 0) {
  2900.     SYSLOG2(LOG_ERR, "Exiting: unable to stat %s: %s.\n",
  2901.            migd_GlobalPdevName, strerror(errno));
  2902.     exit(1);
  2903.     }
  2904. #endif
  2905.     if (lstat(MIGD_LOCK_FILE, &nameAtts) < 0) {
  2906.     SYSLOG2(LOG_ERR, "Exiting: unable to stat %s: %s.\n",
  2907.            MIGD_LOCK_FILE, strerror(errno));
  2908.     exit(1);
  2909.     }
  2910.     if (nameAtts.st_ino != descAtts.st_ino ||
  2911.     nameAtts.st_version != descAtts.st_version) {
  2912.     SYSLOG3(LOG_WARNING,
  2913.            "Exiting: mismatch statting files: name inode <%d,%d>, version %d.\n",
  2914.            nameAtts.st_ino, nameAtts.st_devServerID, nameAtts.st_version);
  2915.     SYSLOG3(LOG_WARNING,
  2916.            "\tdescriptor inode <%d,%d> version %d (another migd running, or server changed file version).\n",
  2917.            descAtts.st_ino, descAtts.st_devServerID, descAtts.st_version);
  2918.     exit(1);
  2919.     }
  2920.  
  2921.     if (global_Debug > 4) {
  2922.     PRINT_PID;
  2923.     fprintf(stderr, "Descriptors matched okay.\n");
  2924.     }
  2925.     
  2926.  
  2927.     checkPoint = fopen(MIGD_CHECKPOINT_FILE, "w+");
  2928.     if (checkPoint == (FILE *) NULL) {
  2929.     SYSLOG1(LOG_WARNING, "SaveCheckPoint - error writing checkpoint: %s.\n",
  2930.            strerror(errno));
  2931.     return;
  2932.     }
  2933.     status = gettimeofday(&tv, (struct timezone *) NULL);
  2934.     if (status == -1) {
  2935.     SYSLOG1(LOG_ERR, "Error in gettimeofday: %s", strerror(errno));
  2936.     exit(1);
  2937.     }
  2938.  
  2939.     if (migd_DoStats) {
  2940.     DumpStats(checkPoint);
  2941.     }
  2942.  
  2943.     for (i = 1; i <= maxKnownHost; i++) {
  2944.     migdPtr = migInfoArray[i];
  2945.     if (migdPtr == (Migd_Info *) NULL ||
  2946.         migdPtr->info.loadVec.timestamp == 0) {
  2947.         continue;
  2948.     }
  2949.     if (fprintf(checkPoint, "%d %d\n", migdPtr->info.hostID,
  2950.             migdPtr->info.loadVec.timestamp) < 0) {
  2951.         SYSLOG1(LOG_WARNING,
  2952.            "SaveCheckPoint - error writing record to checkpoint file: %s.\n",
  2953.            strerror(errno));
  2954.         if (global_Debug == 0) {
  2955.         (void) unlink(MIGD_CHECKPOINT_FILE);
  2956.         }
  2957.     }
  2958.     if (migdPtr->info.state != MIG_HOST_DOWN &&
  2959.         migdPtr->info.loadVec.timestamp < tv.tv_sec - MIG_TIMEOUT) {
  2960.         if (global_Debug > 1) {
  2961.         PRINT_PID;
  2962.         fprintf(stderr,
  2963.                "SaveCheckPoint - marking %s down (curTime %d, updated %d).\n",
  2964.                migdPtr->name, tv.tv_sec,
  2965.                migdPtr->info.loadVec.timestamp);
  2966.         }
  2967.         (void) Global_HostDown(i, 0);
  2968.     } else if (migdPtr->info.loadVec.foreignProcs == 0 &&
  2969.            migdPtr->info.loadVec.allowMigration &&
  2970.            (migdPtr->info.state == MIG_HOST_PART_USED ||
  2971.             migdPtr->info.state == MIG_HOST_FULL)) {
  2972.         if (global_Debug > 1) {
  2973.         PRINT_PID;
  2974.         fprintf(stderr,
  2975.                "SaveCheckPoint - checking %s foreign count.\n",
  2976.                migdPtr->name);
  2977.         }
  2978.         
  2979.         if (migdPtr->flags & MIGD_WAS_EMPTY) {
  2980.         ForceHostIdle(migdPtr);
  2981.         } else {
  2982.         migdPtr->flags |= MIGD_WAS_EMPTY;
  2983.         }
  2984.     } 
  2985.     }
  2986.     fflush(checkPoint);
  2987.     if (fsync(fileno(checkPoint)) < 0) {
  2988.     SYSLOG0(LOG_WARNING, "Error syncing checkpoint file to disk.\n");
  2989.     }
  2990.     (void) fclose(checkPoint);
  2991. }
  2992.     
  2993.  
  2994. /*
  2995.  *----------------------------------------------------------------------
  2996.  *
  2997.  * DumpStats --
  2998.  *
  2999.  *    Write statistics out in ASCII to the checkpoint file.
  3000.  *
  3001.  * Results:
  3002.  *    None.
  3003.  *
  3004.  * Side effects:
  3005.  *    None.
  3006.  *
  3007.  *----------------------------------------------------------------------
  3008.  */
  3009.  
  3010. static void
  3011. DumpStats(file)
  3012.     FILE *file;
  3013. {
  3014.     int i, j;
  3015.  
  3016.     global_Stats.intervals++;
  3017.     
  3018.     fprintf(file, "%% Version %u HasStats %u Interval %u last run on %s.\n",
  3019.         migd_Version, migd_DoStats, global_CheckpointInterval,
  3020.         migd_HostName);
  3021.     fprintf(file, "%% firstRun %u\n", global_Stats.firstRun);
  3022.     fprintf(file, "%% restarts %u\n", global_Stats.restarts);
  3023.     fprintf(file, "%% intervals %u\n", global_Stats.intervals);
  3024.     fprintf(file, "%% maxArchs %u\n", global_Stats.maxArchs);
  3025.     fprintf(file, "%% getLoadRequests %u\n", global_Stats.getLoadRequests);
  3026.     fprintf(file, "%% totalRequests %u\n", global_Stats.totalRequests);
  3027.     fprintf(file, "%% totalObtained %u\n", global_Stats.totalObtained);
  3028.     fprintf(file, "%% numRepeatRequests %u\n", global_Stats.numRepeatRequests);
  3029.     fprintf(file, "%% numRepeatAssignments %u\n",
  3030.         global_Stats.numRepeatAssignments);
  3031.     fprintf(file, "%% numFirstAssignments %u\n",
  3032.         global_Stats.numFirstAssignments);
  3033.     for (i = 0; i < global_Stats.maxArchs; i++) {
  3034.     fprintf(file, "%% arch %u %s\n",
  3035.         i, global_Stats.archStats[i].arch);
  3036.     fprintf(file, "%% \tnumClients %u\n",
  3037.         global_Stats.archStats[i].numClients);
  3038.     fprintf(file, "%% \tgotAll %u\n",
  3039.         global_Stats.archStats[i].gotAll);
  3040.     fprintf(file, "%% \tnonIdleTransitions %u\n",
  3041.         global_Stats.archStats[i].nonIdleTransitions);
  3042.  
  3043.     fprintf(file, "%% \trequested %u %u\n",
  3044.         global_Stats.archStats[i].counters.requested,
  3045.         global_Stats.archStats[i].squared.requested);
  3046.     fprintf(file, "%% \tobtained %u %u\n",
  3047.         global_Stats.archStats[i].counters.obtained,
  3048.         global_Stats.archStats[i].squared.obtained);
  3049.     fprintf(file, "%% \tevicted %u %u\n",
  3050.         global_Stats.archStats[i].counters.evicted,
  3051.         global_Stats.archStats[i].squared.evicted);
  3052.     fprintf(file, "%% \treclaimed %u %u\n",
  3053.         global_Stats.archStats[i].counters.reclaimed,
  3054.         global_Stats.archStats[i].squared.reclaimed);
  3055.     fprintf(file, "%% \ttimeUsed %u %u\n",
  3056.         global_Stats.archStats[i].counters.timeUsed,
  3057.         global_Stats.archStats[i].squared.timeUsed);
  3058.     fprintf(file, "%% \ttimeToEviction %u %u\n",
  3059.         global_Stats.archStats[i].counters.timeToEviction,
  3060.         global_Stats.archStats[i].squared.timeToEviction);
  3061.     fprintf(file, "%% \thostIdleObtained %u %u %u %u\n",
  3062.         global_Stats.archStats[i].counters.hostIdleObtained[MIG_COUNTER_HIGH],
  3063.         global_Stats.archStats[i].counters.hostIdleObtained[MIG_COUNTER_LOW],
  3064.         global_Stats.archStats[i].squared.hostIdleObtained[MIG_COUNTER_HIGH],
  3065.         global_Stats.archStats[i].squared.hostIdleObtained[MIG_COUNTER_LOW]);
  3066.     fprintf(file, "%% \thostIdleEvicted %u %u %u %u\n",
  3067.         global_Stats.archStats[i].counters.hostIdleEvicted[MIG_COUNTER_HIGH],
  3068.         global_Stats.archStats[i].counters.hostIdleEvicted[MIG_COUNTER_LOW],
  3069.         global_Stats.archStats[i].squared.hostIdleEvicted[MIG_COUNTER_HIGH],
  3070.         global_Stats.archStats[i].squared.hostIdleEvicted[MIG_COUNTER_LOW]);
  3071.     fprintf(file, "%% \tidleTimeWhenActive %u %u %u %u\n",
  3072.         global_Stats.archStats[i].counters.idleTimeWhenActive[MIG_COUNTER_HIGH],
  3073.         global_Stats.archStats[i].counters.idleTimeWhenActive[MIG_COUNTER_LOW],
  3074.         global_Stats.archStats[i].squared.idleTimeWhenActive[MIG_COUNTER_HIGH],
  3075.         global_Stats.archStats[i].squared.idleTimeWhenActive[MIG_COUNTER_LOW]);
  3076.  
  3077.     fprintf(file, "%% \trequestDist ");
  3078.     for (j = 0; j <= MIG_MAX_HOSTS_DIST; j++) {
  3079.         fprintf(file, "%u ",
  3080.             global_Stats.archStats[i].requestDist[j]);
  3081.     }
  3082.     fprintf(file, "\n");
  3083.  
  3084.     fprintf(file, "%% \tobtainedDist ");
  3085.     for (j = 0; j <= MIG_MAX_HOSTS_DIST; j++) {
  3086.         fprintf(file, "%u ",
  3087.             global_Stats.archStats[i].obtainedDist[j]);
  3088.     }
  3089.     fprintf(file, "\n");
  3090.  
  3091.     fprintf(file, "%% \thostCounts ");
  3092.     for (j = 0; j < MIG_NUM_STATES; j++) {
  3093.         global_Stats.archStats[i].counters.hostCounts[j] +=
  3094.         hostCounts[i][j];
  3095.         global_Stats.archStats[i].squared.hostCounts[j] +=
  3096.         hostCounts[i][j] * hostCounts[i][j];
  3097.         fprintf(file, "%u %u ",
  3098.             global_Stats.archStats[i].counters.hostCounts[j],
  3099.             global_Stats.archStats[i].squared.hostCounts[j]);
  3100.     }
  3101.     fprintf(file, "\n");
  3102.     }
  3103.     fprintf(file, "%% End of Statistics\n");
  3104.  
  3105. /*
  3106.  *----------------------------------------------------------------------
  3107.  *
  3108.  * ReadStats --
  3109.  *
  3110.  *    Read statistics in ASCII format from the checkpoint file.  
  3111.  *
  3112.  * Results:
  3113.  *    If we are the wrong version, or we hit some error, we return -1.
  3114.  *    That indicates that the caller should just ignore any subsequent
  3115.  *    lines with "%" in them.  0 indicates success.
  3116.  *
  3117.  * Side effects:
  3118.  *    Statistics are reset from last checkpoint.
  3119.  *
  3120.  *----------------------------------------------------------------------
  3121.  */
  3122.  
  3123. static int
  3124. ReadStats(file)
  3125.     FILE *file;
  3126. {
  3127.     int i, j;
  3128.     int numScanned;
  3129.     char buffer[BUFSIZ];
  3130.     int lineNum = 0;
  3131.     int lastVersion;        /* Version of migd that wrote checkpoint. */
  3132.     int lastInterval;        /* Checkpoint interval  of migd that wrote
  3133.                    checkpoint. */
  3134.     int didStats;        /* Whether that migd wrote the statistics. */
  3135.     int maxArchs;        /* Value of global_Stats.maxArchs for that
  3136.                    migd. */
  3137.     int archNum;        /* Index into archTypes array. */
  3138.     char archName[BUFSIZ];    /* Temporary buffer for name, to compare
  3139.                    against our index. */
  3140.     
  3141. /*
  3142.  * Common action to take on bad input.
  3143.  */
  3144. #define BAD_INPUT \
  3145.     if (global_Debug > 1) { \
  3146.     PRINT_PID; \
  3147.     fprintf(stderr, \
  3148.         "ReadStats: bad input on line %d: %s", \
  3149.         lineNum, buffer); \
  3150.     } \
  3151.     return(-1); 
  3152.  
  3153.  
  3154.  
  3155. /*
  3156.  * For each line, read the whole thing into a buffer (1) to make sure
  3157.  * it starts with "%" and (2) to be able to print it out entirely
  3158.  * if there's a problem.
  3159.  */
  3160. #define READLINE \
  3161.     if (fgets(buffer, sizeof(buffer), file) == (char *) NULL) { \
  3162.     if (global_Debug > 1) { \
  3163.         PRINT_PID; \
  3164.         fprintf(stderr, \
  3165.             "ReadStats: end of file at line %d.\n", lineNum); \
  3166.     } \
  3167.     return(-1); \
  3168.     } \
  3169.     lineNum++; \
  3170.     if (buffer[0] != '%') { \
  3171.         BAD_INPUT; \
  3172.     }
  3173.  
  3174.     READLINE;
  3175.     
  3176.     if (global_Debug > 1) {
  3177.     PRINT_PID;
  3178.     fprintf(stderr, "ReadStats: %s", buffer);
  3179.     }
  3180.     
  3181.     numScanned = sscanf(buffer, "%% Version %u HasStats %u Interval %u",
  3182.         &lastVersion, &didStats, &lastInterval);
  3183.     if (numScanned != 3) {
  3184.     BAD_INPUT;
  3185.     }
  3186.     if (lastVersion != migd_Version ||
  3187.     lastInterval != global_CheckpointInterval) {
  3188.     if (global_Debug > 1) { 
  3189.         PRINT_PID; 
  3190.         fprintf(stderr, 
  3191.             "ReadStats: mismatch in migd versions or intervals: ours is %u, %u but last writer\n\tof checkpoint was %u, %u.\n",
  3192.             migd_Version, global_CheckpointInterval,
  3193.             lastVersion, lastInterval); 
  3194.     } 
  3195.     return(-1); 
  3196.     }
  3197.     if (didStats != 1) {
  3198.     if (global_Debug > 1) { 
  3199.         PRINT_PID; 
  3200.         fprintf(stderr, 
  3201.             "ReadStats: last writer of checkpoint didn't do stats.\n"); 
  3202.     } 
  3203.     return(0);
  3204.     }
  3205.  
  3206.  
  3207.     READLINE;
  3208.     numScanned = sscanf(buffer, "%% firstRun %u", &global_Stats.firstRun);
  3209.     if (numScanned != 1) {
  3210.     BAD_INPUT;
  3211.     }
  3212.     
  3213.     READLINE;
  3214.     numScanned = sscanf(buffer, "%% restarts %u", &global_Stats.restarts);
  3215.     if (numScanned != 1) {
  3216.     BAD_INPUT;
  3217.     }
  3218.     global_Stats.restarts++;
  3219.  
  3220.     READLINE;
  3221.     numScanned = sscanf(buffer, "%% intervals %u", &global_Stats.intervals);
  3222.     if (numScanned != 1) {
  3223.     BAD_INPUT;
  3224.     }
  3225.  
  3226.     READLINE;
  3227.     numScanned = sscanf(buffer, "%% maxArchs %u", &maxArchs);
  3228.     if (numScanned != 1) {
  3229.     BAD_INPUT;
  3230.     }
  3231.     if (maxArchs != global_Stats.maxArchs) {
  3232.     if (global_Debug > 1) { 
  3233.         PRINT_PID; 
  3234.         fprintf(stderr, 
  3235.             "ReadStats: discrepancy in number of architectures managed by\n\tmigd; resetting statistics.\n"); 
  3236.     } 
  3237.     return(-1);
  3238.     }
  3239.     
  3240.     READLINE;
  3241.     numScanned = sscanf(buffer, "%% getLoadRequests %u",
  3242.             &global_Stats.getLoadRequests);
  3243.     if (numScanned != 1) {
  3244.     BAD_INPUT;
  3245.     }
  3246.  
  3247.     READLINE;
  3248.     numScanned = sscanf(buffer, "%% totalRequests %u",
  3249.             &global_Stats.totalRequests);
  3250.     if (numScanned != 1) {
  3251.     BAD_INPUT;
  3252.     }
  3253.  
  3254.     READLINE;
  3255.     numScanned = sscanf(buffer, "%% totalObtained %u",
  3256.             &global_Stats.totalObtained);
  3257.     if (numScanned != 1) {
  3258.     BAD_INPUT;
  3259.     }
  3260.  
  3261.     READLINE;
  3262.     numScanned = sscanf(buffer, "%% numRepeatRequests %u",
  3263.             &global_Stats.numRepeatRequests);
  3264.     if (numScanned != 1) {
  3265.     BAD_INPUT;
  3266.     }
  3267.  
  3268.     READLINE;
  3269.     numScanned = sscanf(buffer, "%% numRepeatAssignments %u",
  3270.             &global_Stats.numRepeatAssignments);
  3271.     if (numScanned != 1) {
  3272.     BAD_INPUT;
  3273.     }
  3274.  
  3275.     READLINE;
  3276.     numScanned = sscanf(buffer, "%% numFirstAssignments %u",
  3277.             &global_Stats.numFirstAssignments);
  3278.     if (numScanned != 1) {
  3279.     BAD_INPUT;
  3280.     }
  3281.  
  3282.     for (i = 0; i < maxArchs; i++) {
  3283.     READLINE;
  3284.     numScanned = sscanf(buffer, "%% arch %u %s", &archNum, archName);
  3285.     if (numScanned != 2) {
  3286.         BAD_INPUT;
  3287.     }
  3288.     if (archNum != i || strcmp(archName, global_Stats.archStats[i].arch)) {
  3289.         BAD_INPUT;
  3290.     }
  3291.  
  3292.     READLINE;
  3293.     numScanned = sscanf(buffer, "%% \tnumClients %u",
  3294.         &global_Stats.archStats[i].numClients);
  3295.     if (numScanned != 1) {
  3296.         BAD_INPUT;
  3297.     }
  3298.     
  3299.     READLINE;
  3300.     numScanned = sscanf(buffer, "%% \tgotAll %u",
  3301.         &global_Stats.archStats[i].gotAll);
  3302.     if (numScanned != 1) {
  3303.         BAD_INPUT;
  3304.     }
  3305.     
  3306.     READLINE;
  3307.     numScanned = sscanf(buffer, "%% \tnonIdleTransitions %u",
  3308.         &global_Stats.archStats[i].nonIdleTransitions);
  3309.     if (numScanned != 1) {
  3310.         BAD_INPUT;
  3311.     }
  3312.  
  3313.     READLINE;
  3314.     numScanned = sscanf(buffer, "%% \trequested %u %u",
  3315.         &global_Stats.archStats[i].counters.requested,
  3316.         &global_Stats.archStats[i].squared.requested);
  3317.     if (numScanned != 2) {
  3318.         BAD_INPUT;
  3319.     }
  3320.     READLINE;
  3321.     numScanned = sscanf(buffer, "%% \tobtained %u %u",
  3322.         &global_Stats.archStats[i].counters.obtained,
  3323.         &global_Stats.archStats[i].squared.obtained);
  3324.     if (numScanned != 2) {
  3325.         BAD_INPUT;
  3326.     }
  3327.     READLINE;
  3328.     numScanned = sscanf(buffer, "%% \tevicted %u %u",
  3329.         &global_Stats.archStats[i].counters.evicted,
  3330.         &global_Stats.archStats[i].squared.evicted);
  3331.     if (numScanned != 2) {
  3332.         BAD_INPUT;
  3333.     }
  3334.     READLINE;
  3335.     numScanned = sscanf(buffer, "%% \treclaimed %u %u",
  3336.         &global_Stats.archStats[i].counters.reclaimed,
  3337.         &global_Stats.archStats[i].squared.reclaimed);
  3338.  
  3339.     if (numScanned != 2) {
  3340.         BAD_INPUT;
  3341.     }
  3342.     READLINE;
  3343.     numScanned = sscanf(buffer, "%% \ttimeUsed %u %u",
  3344.         &global_Stats.archStats[i].counters.timeUsed,
  3345.         &global_Stats.archStats[i].squared.timeUsed);
  3346.  
  3347.     if (numScanned != 2) {
  3348.         BAD_INPUT;
  3349.     }
  3350.     READLINE;
  3351.     numScanned = sscanf(buffer, "%% \ttimeToEviction %u %u",
  3352.         &global_Stats.archStats[i].counters.timeToEviction,
  3353.         &global_Stats.archStats[i].squared.timeToEviction);
  3354.  
  3355.     if (numScanned != 2) {
  3356.         BAD_INPUT;
  3357.     }
  3358.     READLINE;
  3359.     numScanned = sscanf(buffer, "%% \thostIdleObtained %u %u %u %u",
  3360.         &global_Stats.archStats[i].counters.hostIdleObtained[MIG_COUNTER_HIGH],
  3361.         &global_Stats.archStats[i].counters.hostIdleObtained[MIG_COUNTER_LOW],
  3362.         &global_Stats.archStats[i].squared.hostIdleObtained[MIG_COUNTER_HIGH],
  3363.         &global_Stats.archStats[i].squared.hostIdleObtained[MIG_COUNTER_LOW]);
  3364.  
  3365.     if (numScanned != 4) {
  3366.         BAD_INPUT;
  3367.     }
  3368.     READLINE;
  3369.     numScanned = sscanf(buffer, "%% \thostIdleEvicted %u %u %u %u",
  3370.         &global_Stats.archStats[i].counters.hostIdleEvicted[MIG_COUNTER_HIGH],
  3371.         &global_Stats.archStats[i].counters.hostIdleEvicted[MIG_COUNTER_LOW],
  3372.         &global_Stats.archStats[i].squared.hostIdleEvicted[MIG_COUNTER_HIGH],
  3373.         &global_Stats.archStats[i].squared.hostIdleEvicted[MIG_COUNTER_LOW]);
  3374.  
  3375.     if (numScanned != 4) {
  3376.         BAD_INPUT;
  3377.     }
  3378.     READLINE;
  3379.     numScanned = sscanf(buffer, "%% \tidleTimeWhenActive %u %u %u %u",
  3380.         &global_Stats.archStats[i].counters.idleTimeWhenActive[MIG_COUNTER_HIGH],
  3381.         &global_Stats.archStats[i].counters.idleTimeWhenActive[MIG_COUNTER_LOW],
  3382.         &global_Stats.archStats[i].squared.idleTimeWhenActive[MIG_COUNTER_HIGH],
  3383.         &global_Stats.archStats[i].squared.idleTimeWhenActive[MIG_COUNTER_LOW]);
  3384.     if (numScanned != 4) {
  3385.         BAD_INPUT;
  3386.     }
  3387.     /*
  3388.      * No easy way to use sscanf to go through a string piece
  3389.      * by piece, so use fscanf.  First for distribution of requests,
  3390.      * then count of hosts.
  3391.      */
  3392.     numScanned = fscanf(file, "%% \trequestDist");
  3393.     if (numScanned < 0) {
  3394.         if (global_Debug > 1) { 
  3395.         PRINT_PID; 
  3396.         fprintf(stderr, 
  3397.             "ReadStats: error scanning requestDist line (%d).\n",
  3398.             lineNum); 
  3399.         } 
  3400.         return(-1);
  3401.     }        
  3402.     for (j = 0; j <= MIG_MAX_HOSTS_DIST; j++) {
  3403.         numScanned = fscanf(file, "%u ",
  3404.                 &global_Stats.archStats[i].requestDist[j]);
  3405.         if (numScanned != 1) {
  3406.         if (global_Debug > 1) { 
  3407.             PRINT_PID; 
  3408.             fprintf(stderr, 
  3409.                 "ReadStats: error scanning requestDist line (%d).\n",
  3410.                 lineNum); 
  3411.         } 
  3412.         return(-1);
  3413.         }        
  3414.     }
  3415.     numScanned = fscanf(file, "\n");
  3416.     if (numScanned < 0) {
  3417.         if (global_Debug > 1) { 
  3418.         PRINT_PID; 
  3419.         fprintf(stderr, 
  3420.             "ReadStats: error scanning requestDist line (%d).\n",
  3421.             lineNum); 
  3422.         } 
  3423.         return(-1);
  3424.     }        
  3425.     lineNum++;
  3426.  
  3427.     numScanned = fscanf(file, "%% \tobtainedDist");
  3428.     if (numScanned < 0) {
  3429.         if (global_Debug > 1) { 
  3430.         PRINT_PID; 
  3431.         fprintf(stderr, 
  3432.             "ReadStats: error scanning obtainedDist line (%d).\n",
  3433.             lineNum); 
  3434.         } 
  3435.         return(-1);
  3436.     }        
  3437.     for (j = 0; j <= MIG_MAX_HOSTS_DIST; j++) {
  3438.         numScanned = fscanf(file, "%u ",
  3439.                 &global_Stats.archStats[i].obtainedDist[j]);
  3440.         if (numScanned != 1) {
  3441.         if (global_Debug > 1) { 
  3442.             PRINT_PID; 
  3443.             fprintf(stderr, 
  3444.                 "ReadStats: error scanning obtainedDist line (%d).\n",
  3445.                 lineNum); 
  3446.         } 
  3447.         return(-1);
  3448.         }        
  3449.     }
  3450.     numScanned = fscanf(file, "\n");
  3451.     if (numScanned < 0) {
  3452.         if (global_Debug > 1) { 
  3453.         PRINT_PID; 
  3454.         fprintf(stderr, 
  3455.             "ReadStats: error scanning obtainedDist line (%d).\n",
  3456.             lineNum); 
  3457.         } 
  3458.         return(-1);
  3459.     }        
  3460.     lineNum++;
  3461.  
  3462.     numScanned = fscanf(file, "%% \thostCounts");
  3463.     if (numScanned < 0) {
  3464.         if (global_Debug > 1) { 
  3465.         PRINT_PID; 
  3466.         fprintf(stderr, 
  3467.             "ReadStats: error scanning hostCounts line (%d).\n",
  3468.             lineNum); 
  3469.         } 
  3470.         return(-1);
  3471.     }        
  3472.     for (j = 0; j < MIG_NUM_STATES; j++) {
  3473.         numScanned = fscanf(file, "%u %u ",
  3474.                 &global_Stats.archStats[i].counters.hostCounts[j],
  3475.                 &global_Stats.archStats[i].squared.hostCounts[j]);
  3476.         if (numScanned != 2) {
  3477.         if (global_Debug > 1) { 
  3478.             PRINT_PID; 
  3479.             fprintf(stderr, 
  3480.                 "ReadStats: error scanning hostCounts line (%d).\n",
  3481.                 lineNum); 
  3482.         } 
  3483.         return(-1);
  3484.         }        
  3485.     }
  3486.     numScanned = fscanf(file, "\n");
  3487.     if (numScanned < 0) {
  3488.         if (global_Debug > 1) { 
  3489.         PRINT_PID; 
  3490.         fprintf(stderr, 
  3491.             "ReadStats: error scanning hostCounts line (%d).\n",
  3492.             lineNum); 
  3493.         } 
  3494.         return(-1);
  3495.     }        
  3496.     lineNum++;
  3497.     }
  3498.     return(0);
  3499.  
  3500.  
  3501.  
  3502. /*
  3503.  *----------------------------------------------------------------------
  3504.  *
  3505.  * CltToMigd --
  3506.  *
  3507.  *    Return the migd pointer corresponding to a host, given its
  3508.  *    cltPtr.  This combines all the sanity checks in a single
  3509.  *    location.
  3510.  *
  3511.  * Results:
  3512.  *    A pointer to the internal Migd_Info record for the host is returned,
  3513.  *    or NULL if the entry doesn't exist.
  3514.  *
  3515.  * Side effects:
  3516.  *    None.
  3517.  *
  3518.  *----------------------------------------------------------------------
  3519.  */
  3520.  
  3521. static Migd_Info *
  3522. CltToMigd(cltPtr)
  3523.     Migd_OpenStreamInfo *cltPtr;
  3524. {
  3525.     Migd_Info *migdPtr;
  3526.  
  3527.     migdPtr = migInfoArray[cltPtr->host];
  3528.     if (migdPtr == (Migd_Info *) NULL) {
  3529.     return((Migd_Info *) NULL);
  3530.     }
  3531.     if (migdPtr->cltPtr != cltPtr) {
  3532.     SYSLOG1(LOG_WARNING,
  3533.            "Mismatch in client information for host %d.\n", cltPtr->host);
  3534.     return((Migd_Info *) NULL);
  3535.     }
  3536.     return(migdPtr);
  3537. }
  3538.  
  3539.  
  3540.  
  3541. /*
  3542.  *----------------------------------------------------------------------
  3543.  *
  3544.  * HostIsIdle --
  3545.  *
  3546.  *    Return whether a host is considered to be at least partly
  3547.  *    idle.  This should be changed to a macro once debugging is over.
  3548.  *
  3549.  * Results:
  3550.  *    A non-zero value is returned if the host referenced by migdPtr
  3551.  *    is considered to be idle, else 0.
  3552.  *
  3553.  * Side effects:
  3554.  *    None.
  3555.  *
  3556.  *----------------------------------------------------------------------
  3557.  */
  3558.  
  3559. static int
  3560. HostIsIdle(migdPtr)
  3561.     Migd_Info *migdPtr;
  3562. {
  3563.     if (global_Debug > 3) {
  3564.     PRINT_PID;
  3565.     fprintf(stderr, "HostIsIdle: %s was ", migdPtr->name);
  3566.     }
  3567.     if (migdPtr->info.state == MIG_HOST_IDLE ||
  3568.     migdPtr->info.state == MIG_HOST_PART_USED) {
  3569.     if (global_Debug > 3) {
  3570.         PRINT_PID;
  3571.         fprintf(stderr, "idle\n");
  3572.     }
  3573.     return(1);
  3574.     }
  3575.     if (global_Debug > 3) {
  3576.     PRINT_PID;
  3577.     fprintf(stderr, "not idle\n");
  3578.     }
  3579.     return(0);
  3580. }
  3581.  
  3582.  
  3583. /*
  3584.  *----------------------------------------------------------------------
  3585.  *
  3586.  * ForceHostIdle --
  3587.  *
  3588.  *    Restore sanity to a host by removing all indications of clients
  3589.  *    associated with the host and then putting it back on the idle list.
  3590.  *    This is necessary if, for example, someone requests a host
  3591.  *    and then doesn't release it.
  3592.  *
  3593.  * Results:
  3594.  *    None.
  3595.  *
  3596.  * Side effects:
  3597.  *    Host is put on idle list.
  3598.  *
  3599.  *----------------------------------------------------------------------
  3600.  */
  3601.  
  3602. static void
  3603. ForceHostIdle(migdPtr)
  3604.     Migd_Info *migdPtr;
  3605. {
  3606.     List_Links *listPtr;
  3607.     RequestInfo *reqPtr;
  3608.  
  3609.     if (global_Debug > 1) {
  3610.     PRINT_PID;
  3611.     fprintf(stderr, "ForceHostIdle: %s now believed to be idle.\n",
  3612.            migdPtr->name);
  3613.     }
  3614.     while (!List_IsEmpty(&migdPtr->clientList)) {
  3615.     listPtr = List_First(&migdPtr->clientList);
  3616.     List_Remove(listPtr);
  3617.     reqPtr = NEXT_HOST_REQUEST_TO_INFO(listPtr);
  3618.     if (global_Debug > 1) {
  3619.         PRINT_PID;
  3620.         fprintf(stderr, "Removing request from process %x.\n",
  3621.            (reqPtr->flags & MIG_PROC_AGENT) ? 
  3622.            reqPtr->client.processID : 
  3623.            reqPtr->client.cltPtr->processID);
  3624.     }
  3625.     /*
  3626.      * This is like an eviction, except no processes are getting evicted
  3627.      * -- we don't even think there are any there.  Instead, we notify
  3628.      * the client that we've revoked its permission to use this host
  3629.      * later on.
  3630.      */
  3631.     RevokePermission(reqPtr, REVOKE_IDLE);
  3632.     free((char *) reqPtr);
  3633.     }
  3634.     migdPtr->flags &= ~(MIGD_CHECK_COUNT | MIGD_WAS_EMPTY);
  3635.     if (HostIsIdle(migdPtr)) {
  3636.     List_Remove((List_Links *) migdPtr);
  3637.     } 
  3638.     InsertIdle(migdPtr);
  3639. }
  3640.  
  3641. /*
  3642.  *----------------------------------------------------------------------
  3643.  *
  3644.  * Global_GetStats --
  3645.  *
  3646.  *    Return the statistics structure to a user process.
  3647.  *
  3648.  * Results:
  3649.  *    0 for success, or an errno indicating the error.
  3650.  *    The statistics, and the size of the buffer, are returned.
  3651.  *
  3652.  * Side effects:
  3653.  *    None.
  3654.  *
  3655.  *----------------------------------------------------------------------
  3656.  */
  3657.  
  3658. /* ARGSUSED */
  3659. int
  3660. Global_GetStats(cltPtr, command, inBuffer, inBufSize, outBuffer,
  3661.            outBufSizePtr)
  3662.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  3663.                    the request. */
  3664.     int command;        /* Ignored. */
  3665.     char *inBuffer;        /* Not used. */
  3666.     int inBufSize;        /* Not used. */
  3667.     char *outBuffer;        /* Buffer to place results. */
  3668.     int *outBufSizePtr;        /* Size of the output buffer. */
  3669. {
  3670.     if (global_Debug > 3) {
  3671.     PRINT_PID;
  3672.     fprintf(stderr, "Global_GetStats called.\n");
  3673.     }
  3674.  
  3675.     if (*outBufSizePtr != sizeof(Mig_Stats)) {
  3676.     if (global_Debug > 0) {
  3677.         SYSLOG3(LOG_WARNING,
  3678.            "Global_GetStats: bad output buffer size (%d, not %d) from process %x\n",
  3679.            *outBufSizePtr, sizeof(Mig_Stats), cltPtr->processID);
  3680.     }
  3681.     return(EINVAL);
  3682.     }
  3683.     bcopy((char *) &global_Stats, outBuffer, sizeof(Mig_Stats));
  3684.     return(0);
  3685. }
  3686.  
  3687. /*
  3688.  *----------------------------------------------------------------------
  3689.  *
  3690.  * Global_ResetStats --
  3691.  *
  3692.  *    Reinitialize the statistics structure to a user process.  This
  3693.  *    is just a stub that takes standard ioctl arguments and calls the
  3694.  *    internal routine.
  3695.  *
  3696.  * Results:
  3697.  *    0 indicates success.
  3698.  *
  3699.  * Side effects:
  3700.  *    Statistics are zeroed.
  3701.  *
  3702.  *----------------------------------------------------------------------
  3703.  */
  3704.  
  3705. /* ARGSUSED */
  3706. int
  3707. Global_ResetStats(cltPtr, command, inBuffer, inBufSize, outBuffer,
  3708.            outBufSizePtr)
  3709.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  3710.                    the request. */
  3711.     int command;        /* Ignored. */
  3712.     char *inBuffer;        /* Not used. */
  3713.     int inBufSize;        /* Not used. */
  3714.     char *outBuffer;        /* Buffer to place results. */
  3715.     int *outBufSizePtr;        /* Size of the output buffer. */
  3716. {
  3717.     if (global_Debug > 1) {
  3718.     PRINT_PID;
  3719.     fprintf(stderr, "Global_ResetStats called.\n");
  3720.     }
  3721.  
  3722.     InitStats();
  3723.  
  3724.     return(0);
  3725. }
  3726.  
  3727.  
  3728.  
  3729. /*
  3730.  *----------------------------------------------------------------------
  3731.  *
  3732.  * Global_SetParms --
  3733.  *
  3734.  *    Set the parameters used by all migration daemons.
  3735.  *
  3736.  * Results:
  3737.  *    0 for success, or an errno indicating the error.
  3738.  *
  3739.  * Side effects:
  3740.  *    Host-specific daemon connections are made readable so
  3741.  *    they know to perform an ioctl to get the info.
  3742.  *
  3743.  *----------------------------------------------------------------------
  3744.  */
  3745.  
  3746. /* ARGSUSED */
  3747. int
  3748. Global_SetParms(cltPtr, command, inBuffer, inBufSize, outBuffer,
  3749.            outBufSizePtr)
  3750.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  3751.                    the request. */
  3752.     int command;        /* Ignored. */
  3753.     char *inBuffer;        /* Buffer to get arguments from. */
  3754.     int inBufSize;        /* Size of the input buffer. */
  3755.     char *outBuffer;        /* Buffer to place results, not used. */
  3756.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  3757. {
  3758.     if (global_Debug > 1) {
  3759.     PRINT_PID;
  3760.     fprintf(stderr, "Global_SetParms called.\n");
  3761.     }
  3762.  
  3763.     /*
  3764.      * XXX need to add this here.
  3765.      */
  3766.     return(EINVAL);
  3767. }
  3768.     
  3769.  
  3770. /*
  3771.  *----------------------------------------------------------------------
  3772.  *
  3773.  * Global_DumpIdleList --
  3774.  *
  3775.  *    For debugging purposes: print an idle list, given the header.
  3776.  *
  3777.  * Results:
  3778.  *    None.
  3779.  *
  3780.  * Side effects:
  3781.  *    None.
  3782.  *
  3783.  *----------------------------------------------------------------------
  3784.  */
  3785.  
  3786. void
  3787. Global_DumpIdleList(hdrPtr)
  3788.     List_Links *hdrPtr;
  3789. {
  3790.     List_Links *itemPtr;
  3791.     Migd_Info  *migdPtr;
  3792.  
  3793.     LIST_FORALL(hdrPtr, itemPtr) {
  3794.     migdPtr = (Migd_Info *) itemPtr;
  3795.     fprintf(stderr, "\t%s idle %d seconds\n", migdPtr->name,
  3796.         migdPtr->info.loadVec.noInput);
  3797.     }
  3798.     fflush(stderr);
  3799. }
  3800.  
  3801.  
  3802.